Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
L
libvncserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
rasky
libvncserver
Commits
1408866c
Commit
1408866c
authored
Aug 25, 2011
by
Gernot Tenchio
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
websockets: Initial HyBi support
parent
02651bac
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
395 additions
and
54 deletions
+395
-54
rfbserver.c
libvncserver/rfbserver.c
+0
-2
sockets.c
libvncserver/sockets.c
+3
-2
websockets.c
libvncserver/websockets.c
+389
-41
rfb.h
rfb/rfb.h
+3
-9
No files found.
libvncserver/rfbserver.c
View file @
1408866c
...
@@ -365,8 +365,6 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
...
@@ -365,8 +365,6 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
cl
->
webSockets
=
FALSE
;
cl
->
webSockets
=
FALSE
;
cl
->
webSocketsBase64
=
FALSE
;
cl
->
webSocketsBase64
=
FALSE
;
cl
->
dblen
=
0
;
cl
->
carrylen
=
0
;
#endif
#endif
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
...
...
libvncserver/sockets.c
View file @
1408866c
...
@@ -647,11 +647,12 @@ rfbWriteExact(rfbClientPtr cl,
...
@@ -647,11 +647,12 @@ rfbWriteExact(rfbClientPtr cl,
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
if
(
cl
->
webSockets
)
{
if
(
cl
->
webSockets
)
{
if
((
len
=
webSocketsEncode
(
cl
,
buf
,
len
))
<
0
)
{
char
*
tmp
=
NULL
;
if
((
len
=
webSocketsEncode
(
cl
,
buf
,
len
,
&
tmp
))
<
0
)
{
rfbErr
(
"WriteExact: WebSockets encode error
\n
"
);
rfbErr
(
"WriteExact: WebSockets encode error
\n
"
);
return
-
1
;
return
-
1
;
}
}
buf
=
cl
->
encodeBuf
;
buf
=
tmp
;
}
}
#endif
#endif
...
...
libvncserver/websockets.c
View file @
1408866c
...
@@ -32,12 +32,90 @@
...
@@ -32,12 +32,90 @@
#include <errno.h>
#include <errno.h>
#include <md5.h>
#include <md5.h>
#include <byteswap.h>
#include "rfbconfig.h"
#include "rfbssl.h"
#include "rfbssl.h"
#if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN
#define WS_NTOH64(n) (n)
#define WS_NTOH32(n) (n)
#define WS_NTOH16(n) (n)
#define WS_HTON64(n) (n)
#define WS_HTON16(n) (n)
#else
#define WS_NTOH64(n) bswap_64(n)
#define WS_NTOH32(n) bswap_32(n)
#define WS_NTOH16(n) bswap_16(n)
#define WS_HTON64(n) bswap_64(n)
#define WS_HTON16(n) bswap_16(n)
#endif
#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 <sys/syscall.h>
static
int
gettid
()
{
return
(
int
)
syscall
(
SYS_gettid
);
}
typedef
struct
ws_ctx_s
{
char
encodeBuf
[
B64LEN
(
UPDATE_BUF_SIZE
)
+
WSHLENMAX
];
/* base64 + maximum frame header length */
char
decodeBuf
[
8192
];
/* TODO: what makes sense? */
char
readbuf
[
8192
];
int
readbufstart
;
int
readbuflen
;
int
dblen
;
char
carryBuf
[
3
];
/* For base64 carry-over */
int
carrylen
;
int
version
;
}
ws_ctx_t
;
typedef
union
ws_mask_s
{
char
c
[
4
];
uint32_t
u
;
}
ws_mask_t
;
typedef
struct
__attribute__
((
__packed__
))
ws_header_s
{
unsigned
char
b0
;
unsigned
char
b1
;
union
{
struct
__attribute__
((
__packed__
))
{
uint16_t
l16
;
ws_mask_t
m16
;
};
struct
__attribute__
((
__packed__
))
{
uint64_t
l64
;
ws_mask_t
m64
;
};
ws_mask_t
m
;
};
}
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 FLASH_POLICY_RESPONSE "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>\n"
#define SZ_FLASH_POLICY_RESPONSE 93
#define SZ_FLASH_POLICY_RESPONSE 93
#define WEBSOCKETS_HANDSHAKE_RESPONSE "HTTP/1.1 101 Web Socket Protocol Handshake\r\n\
/*
* 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\
Upgrade: WebSocket\r\n\
Connection: Upgrade\r\n\
Connection: Upgrade\r\n\
%sWebSocket-Origin: %s\r\n\
%sWebSocket-Origin: %s\r\n\
...
@@ -45,6 +123,14 @@ Connection: Upgrade\r\n\
...
@@ -45,6 +123,14 @@ Connection: Upgrade\r\n\
%sWebSocket-Protocol: %s\r\n\
%sWebSocket-Protocol: %s\r\n\
\r\n%s"
\r\n%s"
#define SERVER_HANDSHAKE_HYBI "HTTP/1.1 101 Switching Protocols\r\n\
Upgrade: websocket\r\n\
Connection: Upgrade\r\n\
Sec-WebSocket-Accept: %s\r\n\
Sec-WebSocket-Protocol: %s\r\n\
\r\n"
#define WEBSOCKETS_CLIENT_CONNECT_WAIT_MS 100
#define WEBSOCKETS_CLIENT_CONNECT_WAIT_MS 100
#define WEBSOCKETS_CLIENT_SEND_WAIT_MS 100
#define WEBSOCKETS_CLIENT_SEND_WAIT_MS 100
#define WEBSOCKETS_MAX_HANDSHAKE_LEN 4096
#define WEBSOCKETS_MAX_HANDSHAKE_LEN 4096
...
@@ -65,6 +151,24 @@ min (int a, int b) {
...
@@ -65,6 +151,24 @@ min (int a, int b) {
return
a
<
b
?
a
:
b
;
return
a
<
b
?
a
:
b
;
}
}
#ifdef LIBVNCSERVER_WITH_CLIENT_GCRYPT
#else
#include <openssl/sha.h>
static
void
webSocketsGenSha1Key
(
char
*
target
,
int
size
,
char
*
key
)
{
SHA_CTX
c
;
unsigned
char
tmp
[
SHA_DIGEST_LENGTH
];
SHA1_Init
(
&
c
);
SHA1_Update
(
&
c
,
key
,
strlen
(
key
));
SHA1_Update
(
&
c
,
GUID
,
sizeof
(
GUID
)
-
1
);
SHA1_Final
(
tmp
,
&
c
);
if
(
-
1
==
__b64_ntop
(
tmp
,
SHA_DIGEST_LENGTH
,
target
,
size
))
rfbErr
(
"b64_ntop failed
\n
"
);
}
#endif
/*
/*
* rfbWebSocketsHandshake is called to handle new WebSockets connections
* rfbWebSocketsHandshake is called to handle new WebSockets connections
*/
*/
...
@@ -126,6 +230,9 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
...
@@ -126,6 +230,9 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
char
prefix
[
5
],
trailer
[
17
];
char
prefix
[
5
],
trailer
[
17
];
char
*
path
=
NULL
,
*
host
=
NULL
,
*
origin
=
NULL
,
*
protocol
=
NULL
;
char
*
path
=
NULL
,
*
host
=
NULL
,
*
origin
=
NULL
,
*
protocol
=
NULL
;
char
*
key1
=
NULL
,
*
key2
=
NULL
,
*
key3
=
NULL
;
char
*
key1
=
NULL
,
*
key2
=
NULL
,
*
key3
=
NULL
;
char
*
sec_ws_origin
=
NULL
;
char
*
sec_ws_key
=
NULL
;
char
sec_ws_version
=
0
;
buf
=
(
char
*
)
malloc
(
WEBSOCKETS_MAX_HANDSHAKE_LEN
);
buf
=
(
char
*
)
malloc
(
WEBSOCKETS_MAX_HANDSHAKE_LEN
);
if
(
!
buf
)
{
if
(
!
buf
)
{
...
@@ -198,16 +305,28 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
...
@@ -198,16 +305,28 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
key2
=
line
+
20
;
key2
=
line
+
20
;
buf
[
len
-
2
]
=
'\0'
;
buf
[
len
-
2
]
=
'\0'
;
/* rfbLog("Got key2: %s\n", key2); */
/* 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
;
protocol
=
line
+
24
;
buf
[
len
-
2
]
=
'\0'
;
buf
[
len
-
2
]
=
'\0'
;
/* rfbLog("Got protocol: %s\n", protocol); */
rfbLog
(
"Got protocol: %s
\n
"
,
protocol
);
}
else
if
((
strncasecmp
(
"sec-websocket-origin: "
,
line
,
min
(
llen
,
22
)))
==
0
)
{
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
;
buf
[
len
-
2
]
=
'\0'
;
}
else
if
((
strncasecmp
(
"sec-websocket-version: "
,
line
,
min
(
llen
,
23
)))
==
0
)
{
sec_ws_version
=
strtol
(
line
+
23
,
NULL
,
10
);
buf
[
len
-
2
]
=
'\0'
;
}
}
linestart
=
len
;
linestart
=
len
;
}
}
}
}
if
(
!
(
path
&&
host
&&
origin
))
{
if
(
!
(
path
&&
host
&&
(
origin
||
sec_ws_origin
)
))
{
rfbErr
(
"webSocketsHandshake: incomplete client handshake
\n
"
);
rfbErr
(
"webSocketsHandshake: incomplete client handshake
\n
"
);
free
(
response
);
free
(
response
);
free
(
buf
);
free
(
buf
);
...
@@ -228,27 +347,40 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
...
@@ -228,27 +347,40 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
* by the client.
* by the client.
*/
*/
if
(
sec_ws_version
)
{
char
accept
[
SHA_DIGEST_LENGTH
*
3
];
rfbLog
(
" - WebSockets client version hybi-%02d
\n
"
,
sec_ws_version
);
webSocketsGenSha1Key
(
accept
,
sizeof
(
accept
),
sec_ws_key
);
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
))
{
if
(
!
(
key1
&&
key2
&&
key3
))
{
rfbLog
(
" - WebSockets client version
75
\n
"
);
rfbLog
(
" - WebSockets client version hixie-
75
\n
"
);
prefix
[
0
]
=
'\0'
;
prefix
[
0
]
=
'\0'
;
trailer
[
0
]
=
'\0'
;
trailer
[
0
]
=
'\0'
;
}
else
{
}
else
{
rfbLog
(
" - WebSockets client version
76
\n
"
);
rfbLog
(
" - WebSockets client version hixie-
76
\n
"
);
snprintf
(
prefix
,
5
,
"Sec-"
);
snprintf
(
prefix
,
5
,
"Sec-"
);
webSocketsGenMd5
(
trailer
,
key1
,
key2
,
key3
);
webSocketsGenMd5
(
trailer
,
key1
,
key2
,
key3
);
}
}
len
=
snprintf
(
response
,
WEBSOCKETS_MAX_HANDSHAKE_LEN
,
snprintf
(
response
,
WEBSOCKETS_MAX_HANDSHAKE_LEN
,
SERVER_HANDSHAKE_HIXIE
,
prefix
,
origin
,
prefix
,
scheme
,
WEBSOCKETS_HANDSHAKE_RESPONSE
,
prefix
,
origin
,
prefix
,
scheme
,
host
,
path
,
prefix
,
protocol
,
trailer
);
host
,
path
,
prefix
,
protocol
,
trailer
);
}
if
(
rfbWriteExact
(
cl
,
response
,
strlen
(
response
)
)
<
0
)
{
if
(
rfbWriteExact
(
cl
,
response
,
len
)
<
0
)
{
rfbErr
(
"webSocketsHandshake: failed sending WebSockets response
\n
"
);
rfbErr
(
"webSocketsHandshake: failed sending WebSockets response
\n
"
);
free
(
response
);
free
(
response
);
free
(
buf
);
free
(
buf
);
return
FALSE
;
return
FALSE
;
}
}
/* rfbLog("webSocketsHandshake: handshake complete\n"); */
rfbLog
(
"webSocketsHandshake: %s
\n
"
,
response
);
free
(
response
);
free
(
buf
);
cl
->
wsctx
=
(
wsCtx
*
)
calloc
(
1
,
sizeof
(
ws_ctx_t
));
((
ws_ctx_t
*
)
cl
->
wsctx
)
->
version
=
sec_ws_version
?
WEBSOCKETS_VERSION_HYBI
:
WEBSOCKETS_VERSION_HIXIE
;
return
TRUE
;
return
TRUE
;
}
}
...
@@ -299,13 +431,15 @@ webSocketsGenMd5(char * target, char *key1, char *key2, char *key3)
...
@@ -299,13 +431,15 @@ webSocketsGenMd5(char * target, char *key1, char *key2, char *key3)
}
}
int
int
webSocketsEncode
(
rfbClientPtr
cl
,
const
char
*
src
,
int
len
)
webSocketsEncode
Hixie
(
rfbClientPtr
cl
,
const
char
*
src
,
int
len
,
char
**
dst
)
{
{
int
i
,
sz
=
0
;
int
i
,
sz
=
0
;
unsigned
char
chr
;
unsigned
char
chr
;
cl
->
encodeBuf
[
sz
++
]
=
'\x00'
;
ws_ctx_t
*
wsctx
=
(
ws_ctx_t
*
)
cl
->
wsctx
;
wsctx
->
encodeBuf
[
sz
++
]
=
'\x00'
;
if
(
cl
->
webSocketsBase64
)
{
if
(
cl
->
webSocketsBase64
)
{
len
=
__b64_ntop
((
unsigned
char
*
)
src
,
len
,
cl
->
encodeBuf
+
sz
,
UPDATE_BUF_SIZE
*
2
);
len
=
__b64_ntop
((
unsigned
char
*
)
src
,
len
,
wsctx
->
encodeBuf
+
sz
,
sizeof
(
wsctx
->
encodeBuf
)
-
(
sz
+
1
)
);
if
(
len
<
0
)
{
if
(
len
<
0
)
{
return
len
;
return
len
;
}
}
...
@@ -315,24 +449,24 @@ webSocketsEncode(rfbClientPtr cl, const char *src, int len)
...
@@ -315,24 +449,24 @@ webSocketsEncode(rfbClientPtr cl, const char *src, int len)
chr
=
src
[
i
];
chr
=
src
[
i
];
if
(
chr
<
128
)
{
if
(
chr
<
128
)
{
if
(
chr
==
0x00
)
{
if
(
chr
==
0x00
)
{
cl
->
encodeBuf
[
sz
++
]
=
'\xc4'
;
wsctx
->
encodeBuf
[
sz
++
]
=
'\xc4'
;
cl
->
encodeBuf
[
sz
++
]
=
'\x80'
;
wsctx
->
encodeBuf
[
sz
++
]
=
'\x80'
;
}
else
{
}
else
{
cl
->
encodeBuf
[
sz
++
]
=
chr
;
wsctx
->
encodeBuf
[
sz
++
]
=
chr
;
}
}
}
else
{
}
else
{
if
(
chr
<
192
)
{
if
(
chr
<
192
)
{
cl
->
encodeBuf
[
sz
++
]
=
'\xc2'
;
wsctx
->
encodeBuf
[
sz
++
]
=
'\xc2'
;
cl
->
encodeBuf
[
sz
++
]
=
chr
;
wsctx
->
encodeBuf
[
sz
++
]
=
chr
;
}
else
{
}
else
{
cl
->
encodeBuf
[
sz
++
]
=
'\xc3'
;
wsctx
->
encodeBuf
[
sz
++
]
=
'\xc3'
;
cl
->
encodeBuf
[
sz
++
]
=
chr
-
64
;
wsctx
->
encodeBuf
[
sz
++
]
=
chr
-
64
;
}
}
}
}
}
}
}
}
cl
->
encodeBuf
[
sz
++
]
=
'\xff'
;
wsctx
->
encodeBuf
[
sz
++
]
=
'\xff'
;
/* rfbLog("<< webSocketsEncode: %d\n", len); */
*
dst
=
wsctx
->
encodeBuf
;
return
sz
;
return
sz
;
}
}
...
@@ -361,18 +495,19 @@ ws_peek(rfbClientPtr cl, char *buf, int len)
...
@@ -361,18 +495,19 @@ ws_peek(rfbClientPtr cl, char *buf, int len)
}
}
int
int
webSocketsDecode
(
rfbClientPtr
cl
,
char
*
dst
,
int
len
)
webSocketsDecode
Hixie
(
rfbClientPtr
cl
,
char
*
dst
,
int
len
)
{
{
int
retlen
=
0
,
n
,
i
,
avail
,
modlen
,
needlen
,
actual
;
int
retlen
=
0
,
n
,
i
,
avail
,
modlen
,
needlen
,
actual
;
char
*
buf
,
*
end
=
NULL
;
char
*
buf
,
*
end
=
NULL
;
unsigned
char
chr
,
chr2
;
unsigned
char
chr
,
chr2
;
ws_ctx_t
*
wsctx
=
(
ws_ctx_t
*
)
cl
->
wsctx
;
buf
=
cl
->
decodeBuf
;
buf
=
wsctx
->
decodeBuf
;
n
=
ws_peek
(
cl
,
buf
,
len
*
2
+
2
);
n
=
ws_peek
(
cl
,
buf
,
len
*
2
+
2
);
if
(
n
<=
0
)
{
if
(
n
<=
0
)
{
rfbErr
(
"%s:
recv
of %d
\n
"
,
__func__
,
n
);
rfbErr
(
"%s:
peek
of %d
\n
"
,
__func__
,
n
);
return
n
;
return
n
;
}
}
...
@@ -406,7 +541,7 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len)
...
@@ -406,7 +541,7 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len)
}
}
avail
=
end
-
buf
;
avail
=
end
-
buf
;
len
-=
cl
->
carrylen
;
len
-=
wsctx
->
carrylen
;
/* Determine how much base64 data we need */
/* Determine how much base64 data we need */
modlen
=
len
+
(
len
+
2
)
/
3
;
modlen
=
len
+
(
len
+
2
)
/
3
;
...
@@ -422,9 +557,9 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len)
...
@@ -422,9 +557,9 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len)
}
}
/* Any carryover from previous decode */
/* Any carryover from previous decode */
for
(
i
=
0
;
i
<
cl
->
carrylen
;
i
++
)
{
for
(
i
=
0
;
i
<
wsctx
->
carrylen
;
i
++
)
{
/* rfbLog("Adding carryover %d\n",
cl
->carryBuf[i]); */
/* rfbLog("Adding carryover %d\n",
wsctx
->carryBuf[i]); */
dst
[
i
]
=
cl
->
carryBuf
[
i
];
dst
[
i
]
=
wsctx
->
carryBuf
[
i
];
retlen
+=
1
;
retlen
+=
1
;
}
}
...
@@ -442,11 +577,11 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len)
...
@@ -442,11 +577,11 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len)
/* Consume the data from socket */
/* Consume the data from socket */
i
=
ws_read
(
cl
,
buf
,
needlen
);
i
=
ws_read
(
cl
,
buf
,
needlen
);
cl
->
carrylen
=
n
-
len
;
wsctx
->
carrylen
=
n
-
len
;
retlen
-=
cl
->
carrylen
;
retlen
-=
wsctx
->
carrylen
;
for
(
i
=
0
;
i
<
cl
->
carrylen
;
i
++
)
{
for
(
i
=
0
;
i
<
wsctx
->
carrylen
;
i
++
)
{
/* rfbLog("Saving carryover %d\n", dst[retlen + i]); */
/* rfbLog("Saving carryover %d\n", dst[retlen + i]); */
cl
->
carryBuf
[
i
]
=
dst
[
retlen
+
i
];
wsctx
->
carryBuf
[
i
]
=
dst
[
retlen
+
i
];
}
}
}
else
{
}
else
{
/* UTF-8 encoded WebSockets stream */
/* UTF-8 encoded WebSockets stream */
...
@@ -509,3 +644,216 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len)
...
@@ -509,3 +644,216 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len)
/* rfbLog("<< webSocketsDecode, retlen: %d\n", retlen); */
/* rfbLog("<< webSocketsDecode, retlen: %d\n", retlen); */
return
retlen
;
return
retlen
;
}
}
int
webSocketsDecodeHybi
(
rfbClientPtr
cl
,
char
*
dst
,
int
len
)
{
char
*
buf
,
*
payload
,
*
rbuf
;
int
ret
=
-
1
,
result
=
-
1
;
int
total
=
0
;
ws_mask_t
mask
;
ws_header_t
*
header
;
int
i
,
j
;
unsigned
char
opcode
;
ws_ctx_t
*
wsctx
=
(
ws_ctx_t
*
)
cl
->
wsctx
;
int
flength
,
fin
,
fhlen
,
blen
;
// 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
->
decodeBuf
;
header
=
(
ws_header_t
*
)
wsctx
->
decodeBuf
;
if
(
-
1
==
(
ret
=
ws_peek
(
cl
,
buf
,
B64LEN
(
len
)
+
WSHLENMAX
)))
{
rfbErr
(
"%s: peek; %m
\n
"
,
__func__
);
goto
spor
;
}
if
(
ret
<
2
)
{
rfbErr
(
"%s: peek; got %d bytes
\n
"
,
__func__
,
ret
);
goto
spor
;
/* Incomplete frame header */
}
opcode
=
header
->
b0
&
0x0f
;
fin
=
(
header
->
b0
&
0x80
)
>>
7
;
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
->
m
;
}
else
if
(
flength
==
126
&&
4
<=
ret
)
{
flength
=
WS_NTOH16
(
header
->
l16
);
fhlen
=
4
;
mask
=
header
->
m16
;
}
else
if
(
flength
==
127
&&
10
<=
ret
)
{
flength
=
WS_NTOH64
(
header
->
l64
);
fhlen
=
10
;
mask
=
header
->
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
)))
{
rfbErr
(
"%s: read; %m"
,
__func__
);
return
ret
;
}
else
if
(
ret
<
total
)
{
/* TODO: hmm? */
rfbLog
(
"%s: read; got partial data
\n
"
,
__func__
);
}
else
{
buf
[
ret
]
=
'\0'
;
}
/* process 1 frame */
for
(
i
=
0
;
i
<
flength
;
i
++
)
{
j
=
i
%
4
;
payload
[
i
]
^=
mask
.
c
[
j
];
}
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
->
decodeBuf
,
sizeof
(
wsctx
->
decodeBuf
))))
{
rfbErr
(
"%s: Base64 decode error; %m
\n
"
,
__func__
);
break
;
}
payload
=
wsctx
->
decodeBuf
;
/* 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
(
"unhandled opcode %d, b0: %02x, b1: %02x
\n
"
,
(
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
;
}
int
webSocketsEncodeHybi
(
rfbClientPtr
cl
,
const
char
*
src
,
int
len
,
char
**
dst
)
{
int
blen
,
ret
=
-
1
,
sz
=
0
;
unsigned
char
opcode
=
'\0'
;
/* TODO: option! */
ws_header_t
*
header
;
ws_ctx_t
*
wsctx
=
(
ws_ctx_t
*
)
cl
->
wsctx
;
/* Optional opcode:
* 0x0 - continuation
* 0x1 - text frame (base64 encode buf)
* 0x2 - binary frame (use raw buf)
* 0x8 - connection close
* 0x9 - ping
* 0xA - pong
**/
if
(
!
len
)
{
rfbLog
(
"%s: nothing to encode
\n
"
,
__func__
);
return
0
;
}
header
=
(
ws_header_t
*
)
wsctx
->
encodeBuf
;
if
(
cl
->
webSocketsBase64
)
{
opcode
=
WS_OPCODE_TEXT_FRAME
;
/* calculate the resulting size */
blen
=
B64LEN
(
len
);
}
else
{
blen
=
len
;
}
header
->
b0
=
0x80
|
(
opcode
&
0x0f
);
if
(
blen
<=
125
)
{
header
->
b1
=
(
uint8_t
)
blen
;
sz
=
2
;
}
else
if
(
blen
<=
65536
)
{
header
->
b1
=
0x7e
;
header
->
l16
=
WS_HTON16
((
uint16_t
)
blen
);
sz
=
4
;
}
else
{
header
->
b1
=
0x7f
;
header
->
l64
=
WS_HTON64
(
blen
);
sz
=
10
;
}
if
(
cl
->
webSocketsBase64
)
{
if
(
-
1
==
(
ret
=
__b64_ntop
((
unsigned
char
*
)
src
,
len
,
wsctx
->
encodeBuf
+
sz
,
sizeof
(
wsctx
->
encodeBuf
)
-
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
->
encodeBuf
+
sz
,
src
,
len
);
ret
=
sz
+
len
;
}
*
dst
=
wsctx
->
encodeBuf
;
return
ret
;
}
int
webSocketsEncode
(
rfbClientPtr
cl
,
const
char
*
src
,
int
len
,
char
**
dst
)
{
ws_ctx_t
*
wsctx
=
(
ws_ctx_t
*
)
cl
->
wsctx
;
if
(
wsctx
->
version
==
WEBSOCKETS_VERSION_HIXIE
)
return
webSocketsEncodeHixie
(
cl
,
src
,
len
,
dst
);
else
return
webSocketsEncodeHybi
(
cl
,
src
,
len
,
dst
);
}
int
webSocketsDecode
(
rfbClientPtr
cl
,
char
*
dst
,
int
len
)
{
ws_ctx_t
*
wsctx
=
(
ws_ctx_t
*
)
cl
->
wsctx
;
if
(
wsctx
->
version
==
WEBSOCKETS_VERSION_HIXIE
)
return
webSocketsDecodeHixie
(
cl
,
dst
,
len
);
else
return
webSocketsDecodeHybi
(
cl
,
dst
,
len
);
}
rfb/rfb.h
View file @
1408866c
...
@@ -419,6 +419,7 @@ typedef struct _rfbStatList {
...
@@ -419,6 +419,7 @@ typedef struct _rfbStatList {
}
rfbStatList
;
}
rfbStatList
;
typedef
struct
_rfbSslCtx
rfbSslCtx
;
typedef
struct
_rfbSslCtx
rfbSslCtx
;
typedef
struct
_wsCtx
wsCtx
;
typedef
struct
_rfbClientRec
{
typedef
struct
_rfbClientRec
{
...
@@ -640,17 +641,10 @@ typedef struct _rfbClientRec {
...
@@ -640,17 +641,10 @@ typedef struct _rfbClientRec {
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
rfbBool
webSockets
;
rfbBool
webSockets
;
rfbBool
webSocketsSSL
;
rfbBool
webSocketsBase64
;
rfbBool
webSocketsBase64
;
rfbSslCtx
*
sslctx
;
rfbSslCtx
*
sslctx
;
wsCtx
*
wsctx
;
char
*
wspath
;
/* Requests path component */
char
*
wspath
;
/* Requests path component */
char
encodeBuf
[
UPDATE_BUF_SIZE
*
2
+
2
];
/* UTF-8 could double it + framing */
char
decodeBuf
[
8192
];
/* TODO: what makes sense? */
int
dblen
;
char
carryBuf
[
3
];
/* For base64 carry-over */
int
carrylen
;
#endif
#endif
}
rfbClientRec
,
*
rfbClientPtr
;
}
rfbClientRec
,
*
rfbClientPtr
;
...
@@ -718,7 +712,7 @@ extern rfbBool rfbSetNonBlocking(int sock);
...
@@ -718,7 +712,7 @@ extern rfbBool rfbSetNonBlocking(int sock);
/* websockets.c */
/* websockets.c */
extern
rfbBool
webSocketsCheck
(
rfbClientPtr
cl
);
extern
rfbBool
webSocketsCheck
(
rfbClientPtr
cl
);
extern
int
webSocketsEncode
(
rfbClientPtr
cl
,
const
char
*
src
,
int
len
);
extern
int
webSocketsEncode
(
rfbClientPtr
cl
,
const
char
*
src
,
int
len
,
char
**
dst
);
extern
int
webSocketsDecode
(
rfbClientPtr
cl
,
char
*
dst
,
int
len
);
extern
int
webSocketsDecode
(
rfbClientPtr
cl
,
char
*
dst
,
int
len
);
#endif
#endif
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment