From: Tim Hardeck <thardeck@suse.de>
To: qemu-devel@nongnu.org
Cc: Tim Hardeck <thardeck@suse.de>, github@martintribe.org
Subject: [Qemu-devel] [PATCH] vnc: added initial websockets support
Date: Fri, 16 Nov 2012 16:13:18 +0100 [thread overview]
Message-ID: <1353078798-6472-2-git-send-email-thardeck@suse.de> (raw)
In-Reply-To: <1353078798-6472-1-git-send-email-thardeck@suse.de>
This patch adds basic Websockets version 13 - RFC 6455 - support to QEMU
VNC. Binary encoding support on the client side is required.
Websockets support in QEMU is enabled by the configure option
--enable-vnc-ws.
Websockets connections are recognized by waiting 500ms for a Websocket
handshake. If no data is received a regular vnc connection is assumed.
SHA1 is required for the handshake which is generated by GnuTLS.
Since using GnuTLS does automatically activate VNC-TLS, which has
warnings about deprecated parts, I have changed the configure script
to disable VNC-TLS if not explicitly enabled.
Parts of the implementation base on Anthony Liguori's QEMU Websockets
patch from 2010 and on Joel Martin's LibVNC Websockets implementation.
Signed-off-by: Tim Hardeck <thardeck@suse.de>
---
configure | 34 +++++++-
ui/Makefile.objs | 1 +
ui/vnc-ws.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
ui/vnc-ws.h | 104 ++++++++++++++++++++++++
ui/vnc.c | 93 ++++++++++++++++++---
ui/vnc.h | 15 ++++
6 files changed, 471 insertions(+), 12 deletions(-)
create mode 100644 ui/vnc-ws.c
create mode 100644 ui/vnc-ws.h
diff --git a/configure b/configure
index 7290f50..d252da5 100755
--- a/configure
+++ b/configure
@@ -154,10 +154,11 @@ vnc="yes"
sparse="no"
uuid=""
vde=""
-vnc_tls=""
+vnc_tls="no"
vnc_sasl=""
vnc_jpeg=""
vnc_png=""
+vnc_ws=""
xen=""
xen_ctrl_version=""
xen_pci_passthrough=""
@@ -703,6 +704,10 @@ for opt do
;;
--enable-vnc-png) vnc_png="yes"
;;
+ --disable-vnc-ws) vnc_ws="no"
+ ;;
+ --enable-vnc-ws) vnc_ws="yes"
+ ;;
--disable-slirp) slirp="no"
;;
--disable-uuid) uuid="no"
@@ -1048,6 +1053,8 @@ echo " --disable-vnc-jpeg disable JPEG lossy compression for VNC server"
echo " --enable-vnc-jpeg enable JPEG lossy compression for VNC server"
echo " --disable-vnc-png disable PNG compression for VNC server (default)"
echo " --enable-vnc-png enable PNG compression for VNC server"
+echo " --disable-vnc-ws disable Websockets support for VNC server"
+echo " --enable-vnc-ws enable Websockets support for VNC server"
echo " --disable-curses disable curses output"
echo " --enable-curses enable curses output"
echo " --disable-curl disable curl connectivity"
@@ -1772,6 +1779,26 @@ EOF
fi
##########################################
+# VNC WS detection
+if test "$vnc" = "yes" -a "$vnc_ws" != "no" ; then
+ cat > $TMPC <<EOF
+#include <gnutls/gnutls.h>
+int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; }
+EOF
+ vnc_ws_cflags=`$pkg_config --cflags gnutls 2> /dev/null`
+ vnc_ws_libs=`$pkg_config --libs gnutls 2> /dev/null`
+ if compile_prog "$vnc_ws_cflags" "$vnc_ws_libs" ; then
+ vnc_ws=yes
+ libs_softmmu="$vnc_ws_libs $libs_softmmu"
+ else
+ if test "$vnc_ws" = "yes" ; then
+ feature_not_found "vnc-ws"
+ fi
+ vnc_ws=no
+ fi
+fi
+
+##########################################
# fnmatch() probe, used for ACL routines
fnmatch="no"
cat > $TMPC << EOF
@@ -3191,6 +3218,7 @@ if test "$vnc" = "yes" ; then
echo "VNC SASL support $vnc_sasl"
echo "VNC JPEG support $vnc_jpeg"
echo "VNC PNG support $vnc_png"
+ echo "VNC WS support $vnc_ws"
fi
if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu"
@@ -3367,6 +3395,10 @@ if test "$vnc_png" = "yes" ; then
echo "CONFIG_VNC_PNG=y" >> $config_host_mak
echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak
fi
+if test "$vnc_ws" = "yes" ; then
+ echo "CONFIG_VNC_WS=y" >> $config_host_mak
+ echo "VNC_WS_CFLAGS=$vnc_ws_cflags" >> $config_host_mak
+fi
if test "$fnmatch" = "yes" ; then
echo "CONFIG_FNMATCH=y" >> $config_host_mak
fi
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index adc07be..58e191b 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -4,6 +4,7 @@ vnc-obj-y += vnc-enc-tight.o vnc-palette.o
vnc-obj-y += vnc-enc-zrle.o
vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
+vnc-obj-$(CONFIG_VNC_WS) += vnc-ws.o
vnc-obj-y += vnc-jobs.o
common-obj-y += keymaps.o
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
new file mode 100644
index 0000000..c40266a
--- /dev/null
+++ b/ui/vnc-ws.c
@@ -0,0 +1,236 @@
+/*
+ * QEMU VNC display driver: Websockets support
+ *
+ * Copyright (C) 2010 Joel Martin
+ * Copyright (C) 2012 Tim Hardeck
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include "vnc.h"
+
+void vnc_recognize_connection_type(void *opaque)
+{
+ VncState *vs = opaque;
+ qemu_del_timer(vs->ws_recognition_timer);
+
+ /*
+ * Regular VNC clients wait for a server response while
+ * Websocket VNC clients send a handshake directly
+ */
+ if (vs->input.offset > 0) {
+ VNC_DEBUG("Websockets Handshake found, using Websockets\n");
+ uint8_t *loc = memmem(vs->input.buffer, vs->input.offset,
+ WS_HANDSHAKE_END, strlen(WS_HANDSHAKE_END));
+ if (loc == NULL) {
+ VNC_DEBUG("Received faulty Websocket header, disconnecting\n");
+ vnc_client_error(vs);
+ return;
+ }
+
+ vncws_process_handshake(vs, vs->input.buffer, vs->input.offset);
+
+ buffer_reset(&vs->input);
+ }
+
+ vnc_init_state(vs);
+}
+
+char *vncws_extract_handshake_entry(const char *header, size_t header_len,
+ const char *name)
+{
+ int name_len = strlen(name);
+ char *begin, *end;
+ begin = memmem(header, header_len, name, name_len);
+ if (begin != NULL) {
+ begin += name_len;
+ end = memmem(begin, header_len - (begin - header), WS_HANDSHAKE_DELIM,
+ strlen(WS_HANDSHAKE_DELIM));
+ if (end != NULL) {
+ return g_strndup(begin, end - begin);
+ }
+ }
+ return NULL;
+}
+
+void vncws_process_handshake(VncState *vs, uint8_t *line, size_t size)
+{
+ char *protocols = vncws_extract_handshake_entry((const char *)line, size,
+ "Sec-WebSocket-Protocol: ");
+ char *version = vncws_extract_handshake_entry((const char *)line, size,
+ "Sec-WebSocket-Version: ");
+ char *key = vncws_extract_handshake_entry((const char *)line, size,
+ "Sec-WebSocket-Key: ");
+
+ if (protocols && version && key
+ && memmem(protocols, strlen(protocols), "binary", 6) != NULL
+ && strcmp(version, WS_SUPPORTED_VERSION) == 0
+ && strlen(key) == WS_CLIENT_KEY_LEN) {
+ vncws_send_handshake_response(vs, key);
+ } else {
+ VNC_DEBUG("Defective Websockets header or unsupported protocol, disconnecting\n");
+ vnc_client_error(vs);
+ }
+
+ g_free(protocols);
+ g_free(version);
+ g_free(key);
+}
+
+void vncws_send_handshake_response(VncState *vs, const char* key)
+{
+ char combined_key[WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1];
+ char response[WS_HANDSHAKE_MAX_LEN];
+ char hash[SHA1_DIGEST_SIZE + 1];
+ char *accept = NULL;
+ size_t hash_size = SHA1_DIGEST_SIZE, response_size = 0;
+ gnutls_datum_t in;
+
+ /* create combined key */
+ pstrcpy(combined_key, WS_CLIENT_KEY_LEN + 1, key);
+ pstrcat(combined_key, WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1, WS_GUID);
+
+ /* hash and encode it*/
+ in.data = (void *)combined_key;
+ in.size = WS_CLIENT_KEY_LEN + WS_GUID_LEN;
+ if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &in, hash, &hash_size)
+ == GNUTLS_E_SUCCESS) {
+ accept = g_base64_encode((const guchar *)hash, SHA1_DIGEST_SIZE);
+ }
+ if(accept == NULL) {
+ VNC_DEBUG("Hashing Websocket combined key failed\n");
+ vnc_client_error(vs);
+ return;
+ }
+
+ /* create handshake response */
+ response_size = snprintf(response, WS_HANDSHAKE_MAX_LEN, WS_HANDSHAKE, accept);
+ g_free(accept);
+
+ vnc_write(vs, response, response_size);
+ vnc_flush(vs);
+
+ vs->encode_ws = 1;
+}
+
+void vncws_encode_frame(Buffer *output, const void *payload,
+ const size_t payload_size)
+{
+ size_t header_size = 0;
+ unsigned char opcode = WS_OPCODE_BINARY_FRAME;
+ char header_buf[WS_HEAD_MAX_LEN];
+ ws_header_t *header = (ws_header_t *)header_buf;
+
+ if (!payload_size) {
+ return;
+ }
+
+ header->b0 = 0x80 | (opcode & 0x0f);
+ if (payload_size <= 125) {
+ header->b1 = (uint8_t)payload_size;
+ header_size = 2;
+ } else if (payload_size < 65536) {
+ header->b1 = 0x7e;
+ header->u.s16.l16 = WS_HTON16((uint16_t)payload_size);
+ header_size = 4;
+ } else {
+ header->b1 = 0x7f;
+ header->u.s64.l64 = WS_HTON64(payload_size);
+ header_size = 10;
+ }
+
+ buffer_reserve(output, header_size + payload_size);
+ buffer_append(output, header_buf, header_size);
+ buffer_append(output, payload, payload_size);
+}
+
+int vncws_decode_frame(Buffer *input, uint8_t **payload,
+ size_t *payload_size, size_t *frame_size)
+{
+ unsigned char opcode = 0, fin = 0, has_mask = 0;
+ uint32_t *payload32;
+ size_t header_size = 0;
+ ws_header_t *header = (ws_header_t *)input->buffer;
+ ws_mask_t mask;
+ int mask_size = 0;
+ int i;
+
+ if (input->offset < WS_HEAD_MIN_LEN) {
+ /* header not complete */
+ return 0;
+ }
+
+ fin = (header->b0 & 0x80) >> 7;
+ opcode = header->b0 & 0x0f;
+ has_mask = (header->b1 & 0x80) >> 7;
+ *payload_size = header->b1 & 0x7f;
+
+ if (opcode == WS_OPCODE_CLOSE) {
+ /* disconnect */
+ return -1;
+ }
+
+ /* Websocket frame sanity check:
+ * * Websocket fragmentation is not supported.
+ * * All websockets frames sent by a client have to be masked.
+ * * Only binary encoding is supported.
+ */
+ if (!fin || !has_mask || opcode != WS_OPCODE_BINARY_FRAME) {
+ VNC_DEBUG("Received faulty/unsupported Websocket frame\n");
+ return -2;
+ }
+
+ mask_size = 4 * has_mask;
+
+ if (*payload_size < 126) {
+ header_size = 2;
+ mask = header->u.m;
+ } else if (*payload_size == 126 && input->offset >= 4 + mask_size) {
+ *payload_size = WS_NTOH16(header->u.s16.l16);
+ header_size = 4;
+ mask = header->u.s16.m16;
+ } else if (*payload_size == 127 && input->offset >= 10 + mask_size) {
+ *payload_size = WS_NTOH64(header->u.s64.l64);
+ header_size = 10;
+ mask = header->u.s64.m64;
+ } else {
+ /* header not complete */
+ return 0;
+ }
+
+ header_size += mask_size;
+ *frame_size = header_size + *payload_size;
+
+ if (input->offset < *frame_size) {
+ /* frame not complete */
+ return 0;
+ }
+
+ *payload = input->buffer + header_size;
+
+ /* unmask frame */
+ /* process 1 frame (32 bit op) */
+ payload32 = (uint32_t *)(*payload);
+ for (i = 0; i < *payload_size / 4; i++) {
+ payload32[i] ^= mask.u;
+ }
+ /* process the remaining bytes (if any) */
+ for (i *= 4; i < *payload_size; i++) {
+ (*payload)[i] ^= mask.c[i % 4];
+ }
+
+ return 1;
+}
diff --git a/ui/vnc-ws.h b/ui/vnc-ws.h
new file mode 100644
index 0000000..88f9f8b
--- /dev/null
+++ b/ui/vnc-ws.h
@@ -0,0 +1,104 @@
+/*
+ * QEMU VNC display driver: Websockets support
+ *
+ * Copyright (C) 2010 Joel Martin
+ * Copyright (C) 2012 Tim Hardeck
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifndef __QEMU_VNC_WS_H
+#define __QEMU_VNC_WS_H
+
+#ifndef CONFIG_VNC_TLS
+#include <gnutls/gnutls.h>
+#endif
+
+#define B64LEN(__x) (((__x + 2) / 3) * 12 / 3)
+#define SHA1_DIGEST_SIZE 20
+
+#define WS_HANDSHAKE_TIMEOUT 500
+
+#define WS_ACCEPT_LEN (B64LEN(SHA1_DIGEST_SIZE) + 1)
+#define WS_CLIENT_KEY_LEN 24
+#define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+#define WS_GUID_LEN strlen(WS_GUID)
+
+#define WS_HANDSHAKE_MAX_LEN 192
+#define WS_HANDSHAKE "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: binary\r\n\
+\r\n"
+#define WS_HANDSHAKE_DELIM "\r\n"
+#define WS_HANDSHAKE_END "\r\n\r\n"
+#define WS_SUPPORTED_VERSION "13"
+
+#define WS_HEAD_MIN_LEN 2
+#define WS_HEAD_MAX_LEN 14 /* 2 + sizeof(uint64_t) + sizeof(uint32_t) */
+
+#define WS_HTON64(n) htobe64(n)
+#define WS_HTON16(n) htobe16(n)
+#define WS_NTOH16(n) htobe16(n)
+#define WS_NTOH64(n) htobe64(n)
+
+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 = 0x1,
+ WS_OPCODE_BINARY_FRAME = 0x2,
+ WS_OPCODE_CLOSE = 0x8,
+ WS_OPCODE_PING = 0x9,
+ WS_OPCODE_PONG = 0xA
+};
+
+void vnc_recognize_connection_type(void *opaque);
+char *vncws_extract_handshake_entry(const char *header, size_t header_len,
+ const char *name);
+void vncws_process_handshake(VncState *vs, uint8_t *line, size_t size);
+void vncws_send_handshake_response(VncState *vs, const char* key);
+void vncws_encode_frame(Buffer *output, const void *payload,
+ const size_t payload_size);
+int vncws_decode_frame(Buffer *input, uint8_t **payload,
+ size_t *payload_size, size_t *frame_size);
+
+#endif /* __QEMU_VNC_WS_H */
diff --git a/ui/vnc.c b/ui/vnc.c
index 61f120e..6d57888 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -510,6 +510,13 @@ void buffer_append(Buffer *buffer, const void *data, size_t len)
buffer->offset += len;
}
+void buffer_advance(Buffer *buf, size_t len)
+{
+ memmove(buf->buffer, buf->buffer + len,
+ (buf->offset - len));
+ buf->offset -= len;
+}
+
static void vnc_desktop_resize(VncState *vs)
{
DisplayState *ds = vs->ds;
@@ -1027,6 +1034,9 @@ static void vnc_disconnect_finish(VncState *vs)
buffer_free(&vs->input);
buffer_free(&vs->output);
+#ifdef CONFIG_VNC_WS
+ buffer_free(&vs->ws_input);
+#endif
qobject_decref(vs->info);
@@ -1166,8 +1176,7 @@ static long vnc_client_write_plain(VncState *vs)
if (!ret)
return 0;
- memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
- vs->output.offset -= ret;
+ buffer_advance(&vs->output, ret);
if (vs->output.offset == 0) {
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
@@ -1289,6 +1298,7 @@ void vnc_client_read(void *opaque)
{
VncState *vs = opaque;
long ret;
+ Buffer *buf;
#ifdef CONFIG_VNC_SASL
if (vs->sasl.conn && vs->sasl.runSSF)
@@ -1302,19 +1312,49 @@ void vnc_client_read(void *opaque)
return;
}
- while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
+#ifdef CONFIG_VNC_WS
+ if (vs->encode_ws) {
+ uint8_t *payload;
+ size_t payload_size, frame_size;
+
+ /* make sure that nothing is left in the input buffer */
+ do {
+ ret = vncws_decode_frame(&vs->input, &payload,
+ &payload_size, &frame_size);
+
+ if (ret == 0) {
+ /* not enough data to process, wait for more */
+ return;
+ } else if (ret == -1) {
+ vnc_disconnect_start(vs);
+ return;
+ } else if (ret == -2) {
+ vnc_client_error(vs);
+ return;
+ }
+
+ buffer_reserve(&vs->ws_input, payload_size);
+ buffer_append(&vs->ws_input, payload, payload_size);
+
+ buffer_advance(&vs->input, frame_size);
+ } while (vs->input.offset > 0);
+ buf = &vs->ws_input;
+ } else
+#endif /* CONFIG_VNC_WS */
+ buf = &vs->input;
+
+ while (vs->read_handler && buf->offset >= vs->read_handler_expect) {
size_t len = vs->read_handler_expect;
int ret;
- ret = vs->read_handler(vs, vs->input.buffer, len);
+ ret = vs->read_handler(vs, buf->buffer, len);
if (vs->csock == -1) {
vnc_disconnect_finish(vs);
return;
}
if (!ret) {
- memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
- vs->input.offset -= len;
+ buffer_advance(buf, len);
} else {
vs->read_handler_expect = ret;
}
@@ -1323,13 +1363,26 @@ void vnc_client_read(void *opaque)
void vnc_write(VncState *vs, const void *data, size_t len)
{
- buffer_reserve(&vs->output, len);
+#ifdef CONFIG_VNC_WS
+ if (vs->encode_ws) {
+ if (vs->csock != -1 && buffer_empty(&vs->output)) {
+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read,
+ vnc_client_write, vs);
+ }
+ vncws_encode_frame(&vs->output, data, len);
+ } else {
+#endif /* CONFIG_VNC_WS */
+ buffer_reserve(&vs->output, len);
- if (vs->csock != -1 && buffer_empty(&vs->output)) {
- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
- }
+ if (vs->csock != -1 && buffer_empty(&vs->output)) {
+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read,
+ vnc_client_write, vs);
+ }
- buffer_append(&vs->output, data, len);
+ buffer_append(&vs->output, data, len);
+#ifdef CONFIG_VNC_WS
+ }
+#endif
}
void vnc_write_s32(VncState *vs, int32_t value)
@@ -2691,6 +2744,24 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth)
vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
vs->vd = vd;
+
+#ifdef CONFIG_VNC_WS
+ /* Recognize connection type
+ *
+ * Regular VNC clients wait for a server response while
+ * Websocket VNC clients send a handshake directly
+ */
+ vs->ws_recognition_timer = qemu_new_timer_ms(rt_clock,
+ vnc_recognize_connection_type, vs);
+ qemu_mod_timer(vs->ws_recognition_timer, qemu_get_clock_ms(rt_clock)
+ + WS_HANDSHAKE_TIMEOUT);
+}
+
+void vnc_init_state(VncState *vs)
+{
+ VncDisplay *vd = vs->vd;
+#endif /* CONFIG_VNC_WS */
+
vs->ds = vd->ds;
vs->last_x = -1;
vs->last_y = -1;
diff --git a/ui/vnc.h b/ui/vnc.h
index 6141e88..86acb6b 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -99,6 +99,9 @@ typedef struct VncDisplay VncDisplay;
#ifdef CONFIG_VNC_SASL
#include "vnc-auth-sasl.h"
#endif
+#ifdef CONFIG_VNC_WS
+#include "vnc-ws.h"
+#endif
struct VncRectStat
{
@@ -269,11 +272,18 @@ struct VncState
#ifdef CONFIG_VNC_SASL
VncStateSASL sasl;
#endif
+#ifdef CONFIG_VNC_WS
+ QEMUTimer *ws_recognition_timer;
+ int encode_ws;
+#endif
QObject *info;
Buffer output;
Buffer input;
+#ifdef CONFIG_VNC_WS
+ Buffer ws_input;
+#endif
/* current output mode information */
VncWritePixels *write_pixels;
PixelFormat client_pf;
@@ -505,11 +515,16 @@ int vnc_client_io_error(VncState *vs, int ret, int last_errno);
void start_client_init(VncState *vs);
void start_auth_vnc(VncState *vs);
+#ifdef CONFIG_VNC_WS
+void vnc_init_state(VncState *vs);
+#endif
+
/* Buffer management */
void buffer_reserve(Buffer *buffer, size_t len);
void buffer_reset(Buffer *buffer);
void buffer_free(Buffer *buffer);
void buffer_append(Buffer *buffer, const void *data, size_t len);
+void buffer_advance(Buffer *buf, size_t len);
/* Misc helpers */
--
1.7.10.4
next prev parent reply other threads:[~2012-11-16 15:14 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-11-16 15:13 [Qemu-devel] [PATCH] vnc: added initial websockets support Tim Hardeck
2012-11-16 15:13 ` Tim Hardeck [this message]
2012-11-18 9:31 ` Stefan Hajnoczi
2012-11-18 23:29 ` Tim Hardeck
2012-11-19 8:56 ` Gerd Hoffmann
2012-11-19 10:09 ` Tim Hardeck
2012-11-19 9:07 ` Stefan Hajnoczi
2012-11-19 10:00 ` Tim Hardeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1353078798-6472-2-git-send-email-thardeck@suse.de \
--to=thardeck@suse.de \
--cc=github@martintribe.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.