diff options
Diffstat (limited to 'main/xen/qemu-xen-websocket.patch')
-rw-r--r-- | main/xen/qemu-xen-websocket.patch | 960 |
1 files changed, 0 insertions, 960 deletions
diff --git a/main/xen/qemu-xen-websocket.patch b/main/xen/qemu-xen-websocket.patch deleted file mode 100644 index aa6446e86d..0000000000 --- a/main/xen/qemu-xen-websocket.patch +++ /dev/null @@ -1,960 +0,0 @@ ---- xen-4.3.0.orig/tools/Makefile -+++ xen-4.3.0/tools/Makefile -@@ -203,6 +203,7 @@ - --docdir=$(PREFIX)/share/doc \ - --sysconfdir=/etc/qemu \ - --disable-kvm \ -+ --enable-vnc-ws \ - --disable-docs \ - --python=$(PYTHON) \ - $(IOEMU_CONFIGURE_CROSS); \ ---- xen-4.3.0.orig/tools/qemu-xen/configure -+++ xen-4.3.0/tools/qemu-xen/configure -@@ -158,6 +158,7 @@ - vnc_sasl="" - vnc_jpeg="" - vnc_png="" -+vnc_ws="" - xen="" - xen_ctrl_version="" - xen_pci_passthrough="" -@@ -703,6 +704,10 @@ - ;; - --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 " --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" -@@ -1692,8 +1699,8 @@ - fi - - ########################################## --# VNC TLS detection --if test "$vnc" = "yes" -a "$vnc_tls" != "no" ; then -+# VNC TLS/WS detection -+if test "$vnc" = "yes" -a \( "$vnc_tls" != "no" -o "$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; } -@@ -1701,13 +1708,22 @@ - vnc_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null` - vnc_tls_libs=`$pkg_config --libs gnutls 2> /dev/null` - if compile_prog "$vnc_tls_cflags" "$vnc_tls_libs" ; then -- vnc_tls=yes -+ if test "$vnc_tls" != "no" ; then -+ vnc_tls=yes -+ fi -+ if test "$vnc_ws" != "no" ; then -+ vnc_ws=yes -+ fi - libs_softmmu="$vnc_tls_libs $libs_softmmu" - else - if test "$vnc_tls" = "yes" ; then - feature_not_found "vnc-tls" - fi -+ if test "$vnc_ws" = "yes" ; then -+ feature_not_found "vnc-ws" -+ fi - vnc_tls=no -+ vnc_ws=no - fi - fi - -@@ -3209,6 +3225,7 @@ - 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" -@@ -3384,6 +3401,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 ---- xen-4.3.0.orig/tools/qemu-xen/qemu-options.hx -+++ xen-4.3.0/tools/qemu-xen/qemu-options.hx -@@ -1096,6 +1096,14 @@ - connections (@var{host}:@var{d},@code{reverse}), the @var{d} argument - is a TCP port number, not a display number. - -+@item websocket -+ -+Opens an additional TCP listening port dedicated to VNC Websocket connections. -+By defintion the Websocket port is 5700+@var{display}. If @var{host} is -+specified connections will only be allowed from this host. -+As an alternative the Websocket port could be specified by using -+@code{websocket}=@var{port}. -+ - @item password - - Require that password based authentication is used for client connections. ---- xen-4.3.0.orig/tools/qemu-xen/qemu-options.hx.orig -+++ xen-4.3.0/tools/qemu-xen/qemu-options.hx.orig -@@ -2045,18 +2045,13 @@ - devices. - - Syntax for specifying a sheepdog device --@table @list --``sheepdog:<vdiname>'' -- --``sheepdog:<vdiname>:<snapid>'' -- --``sheepdog:<vdiname>:<tag>'' -- --``sheepdog:<host>:<port>:<vdiname>'' -- --``sheepdog:<host>:<port>:<vdiname>:<snapid>'' -- --``sheepdog:<host>:<port>:<vdiname>:<tag>'' -+@table @code -+@item sheepdog:<vdiname> -+@item sheepdog:<vdiname>:<snapid> -+@item sheepdog:<vdiname>:<tag> -+@item sheepdog:<host>:<port>:<vdiname> -+@item sheepdog:<host>:<port>:<vdiname>:<snapid> -+@item sheepdog:<host>:<port>:<vdiname>:<tag> - @end table - - Example ---- xen-4.3.0.orig/tools/qemu-xen/ui/Makefile.objs -+++ xen-4.3.0/tools/qemu-xen/ui/Makefile.objs -@@ -4,6 +4,7 @@ - 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 ---- /dev/null -+++ xen-4.3.0/tools/qemu-xen/ui/vnc-ws.c -@@ -0,0 +1,284 @@ -+/* -+ * 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, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#include "vnc.h" -+ -+void vncws_handshake_read(void *opaque) -+{ -+ VncState *vs = opaque; -+ uint8_t *handshake_end; -+ long ret; -+ buffer_reserve(&vs->ws_input, 4096); -+ ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096); -+ -+ if (!ret) { -+ if (vs->csock == -1) { -+ vnc_disconnect_finish(vs); -+ } -+ return; -+ } -+ vs->ws_input.offset += ret; -+ -+ handshake_end = (uint8_t *)g_strstr_len((char *)vs->ws_input.buffer, -+ vs->ws_input.offset, WS_HANDSHAKE_END); -+ if (handshake_end) { -+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); -+ vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset); -+ buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer + -+ strlen(WS_HANDSHAKE_END)); -+ } -+} -+ -+ -+long vnc_client_read_ws(VncState *vs) -+{ -+ int ret, err; -+ uint8_t *payload; -+ size_t payload_size, frame_size; -+ VNC_DEBUG("Read websocket %p size %zd offset %zd\n", vs->ws_input.buffer, -+ vs->ws_input.capacity, vs->ws_input.offset); -+ buffer_reserve(&vs->ws_input, 4096); -+ ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096); -+ if (!ret) { -+ return 0; -+ } -+ vs->ws_input.offset += ret; -+ -+ /* make sure that nothing is left in the ws_input buffer */ -+ do { -+ err = vncws_decode_frame(&vs->ws_input, &payload, -+ &payload_size, &frame_size); -+ if (err <= 0) { -+ return err; -+ } -+ -+ buffer_reserve(&vs->input, payload_size); -+ buffer_append(&vs->input, payload, payload_size); -+ -+ buffer_advance(&vs->ws_input, frame_size); -+ } while (vs->ws_input.offset > 0); -+ -+ return ret; -+} -+ -+long vnc_client_write_ws(VncState *vs) -+{ -+ long ret; -+ VNC_DEBUG("Write WS: Pending output %p size %zd offset %zd\n", -+ vs->output.buffer, vs->output.capacity, vs->output.offset); -+ vncws_encode_frame(&vs->ws_output, vs->output.buffer, vs->output.offset); -+ buffer_reset(&vs->output); -+ ret = vnc_client_write_buf(vs, vs->ws_output.buffer, vs->ws_output.offset); -+ if (!ret) { -+ return 0; -+ } -+ -+ buffer_advance(&vs->ws_output, ret); -+ -+ if (vs->ws_output.offset == 0) { -+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); -+ } -+ -+ return ret; -+} -+ -+static char *vncws_extract_handshake_entry(const char *handshake, -+ size_t handshake_len, const char *name) -+{ -+ char *begin, *end, *ret = NULL; -+ char *line = g_strdup_printf("%s%s: ", WS_HANDSHAKE_DELIM, name); -+ begin = g_strstr_len(handshake, handshake_len, line); -+ if (begin != NULL) { -+ begin += strlen(line); -+ end = g_strstr_len(begin, handshake_len - (begin - handshake), -+ WS_HANDSHAKE_DELIM); -+ if (end != NULL) { -+ ret = g_strndup(begin, end - begin); -+ } -+ } -+ g_free(line); -+ return ret; -+} -+ -+static void vncws_send_handshake_response(VncState *vs, const char* key) -+{ -+ char combined_key[WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1]; -+ char hash[SHA1_DIGEST_LEN]; -+ size_t hash_size = SHA1_DIGEST_LEN; -+ char *accept = NULL, *response = NULL; -+ gnutls_datum_t in; -+ -+ g_strlcpy(combined_key, key, WS_CLIENT_KEY_LEN + 1); -+ g_strlcat(combined_key, WS_GUID, WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1); -+ -+ /* 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((guchar *)hash, SHA1_DIGEST_LEN); -+ } -+ if (accept == NULL) { -+ VNC_DEBUG("Hashing Websocket combined key failed\n"); -+ vnc_client_error(vs); -+ return; -+ } -+ -+ response = g_strdup_printf(WS_HANDSHAKE, accept); -+ vnc_write(vs, response, strlen(response)); -+ vnc_flush(vs); -+ -+ g_free(accept); -+ g_free(response); -+ -+ vs->encode_ws = 1; -+ vnc_init_state(vs); -+} -+ -+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 -+ && g_strrstr(protocols, "binary") -+ && !strcmp(version, WS_SUPPORTED_VERSION) -+ && strlen(key) == WS_CLIENT_KEY_LEN) { -+ vncws_send_handshake_response(vs, key); -+ } else { -+ VNC_DEBUG("Defective Websockets header or unsupported protocol\n"); -+ vnc_client_error(vs); -+ } -+ -+ g_free(protocols); -+ g_free(version); -+ g_free(key); -+} -+ -+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; -+ union { -+ char buf[WS_HEAD_MAX_LEN]; -+ WsHeader ws; -+ } header; -+ -+ if (!payload_size) { -+ return; -+ } -+ -+ header.ws.b0 = 0x80 | (opcode & 0x0f); -+ if (payload_size <= 125) { -+ header.ws.b1 = (uint8_t)payload_size; -+ header_size = 2; -+ } else if (payload_size < 65536) { -+ header.ws.b1 = 0x7e; -+ header.ws.u.s16.l16 = cpu_to_be16((uint16_t)payload_size); -+ header_size = 4; -+ } else { -+ header.ws.b1 = 0x7f; -+ header.ws.u.s64.l64 = cpu_to_be64(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; -+ size_t header_size = 0; -+ uint32_t *payload32; -+ WsHeader *header = (WsHeader *)input->buffer; -+ WsMask mask; -+ int i; -+ -+ if (input->offset < WS_HEAD_MIN_LEN + 4) { -+ /* 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; -+ } -+ -+ if (*payload_size < 126) { -+ header_size = 6; -+ mask = header->u.m; -+ } else if (*payload_size == 126 && input->offset >= 8) { -+ *payload_size = be16_to_cpu(header->u.s16.l16); -+ header_size = 8; -+ mask = header->u.s16.m16; -+ } else if (*payload_size == 127 && input->offset >= 14) { -+ *payload_size = be64_to_cpu(header->u.s64.l64); -+ header_size = 14; -+ mask = header->u.s64.m64; -+ } else { -+ /* header not complete */ -+ return 0; -+ } -+ -+ *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; -+} ---- /dev/null -+++ xen-4.3.0/tools/qemu-xen/ui/vnc-ws.h -@@ -0,0 +1,86 @@ -+/* -+ * 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, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#ifndef __QEMU_UI_VNC_WS_H -+#define __QEMU_UI_VNC_WS_H -+ -+#include <gnutls/gnutls.h> -+ -+#define B64LEN(__x) (((__x + 2) / 3) * 12 / 3) -+#define SHA1_DIGEST_LEN 20 -+ -+#define WS_ACCEPT_LEN (B64LEN(SHA1_DIGEST_LEN) + 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 "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 sizeof(uint16_t) -+#define WS_HEAD_MAX_LEN (WS_HEAD_MIN_LEN + sizeof(uint64_t) + sizeof(uint32_t)) -+ -+typedef union WsMask { -+ char c[4]; -+ uint32_t u; -+} WsMask; -+ -+typedef struct QEMU_PACKED WsHeader { -+ unsigned char b0; -+ unsigned char b1; -+ union { -+ struct QEMU_PACKED { -+ uint16_t l16; -+ WsMask m16; -+ } s16; -+ struct QEMU_PACKED { -+ uint64_t l64; -+ WsMask m64; -+ } s64; -+ WsMask m; -+ } u; -+} WsHeader; -+ -+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 vncws_handshake_read(void *opaque); -+long vnc_client_write_ws(VncState *vs); -+long vnc_client_read_ws(VncState *vs); -+void vncws_process_handshake(VncState *vs, uint8_t *line, size_t size); -+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_UI_VNC_WS_H */ ---- xen-4.3.0.orig/tools/qemu-xen/ui/vnc.c -+++ xen-4.3.0/tools/qemu-xen/ui/vnc.c -@@ -420,7 +420,6 @@ - static int vnc_update_client(VncState *vs, int has_dirty); - static int vnc_update_client_sync(VncState *vs, int has_dirty); - static void vnc_disconnect_start(VncState *vs); --static void vnc_disconnect_finish(VncState *vs); - static void vnc_init_timer(VncDisplay *vd); - static void vnc_remove_timer(VncDisplay *vd); - -@@ -486,7 +485,7 @@ - return buffer->offset == 0; - } - --static uint8_t *buffer_end(Buffer *buffer) -+uint8_t *buffer_end(Buffer *buffer) - { - return buffer->buffer + buffer->offset; - } -@@ -510,6 +509,13 @@ - 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; -@@ -1016,7 +1022,7 @@ - vs->csock = -1; - } - --static void vnc_disconnect_finish(VncState *vs) -+void vnc_disconnect_finish(VncState *vs) - { - int i; - -@@ -1027,6 +1033,10 @@ - - buffer_free(&vs->input); - buffer_free(&vs->output); -+#ifdef CONFIG_VNC_WS -+ buffer_free(&vs->ws_input); -+ buffer_free(&vs->ws_output); -+#endif /* CONFIG_VNC_WS */ - - qobject_decref(vs->info); - -@@ -1166,8 +1176,7 @@ - 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); -@@ -1193,7 +1202,16 @@ - vnc_client_write_sasl(vs); - } else - #endif /* CONFIG_VNC_SASL */ -- vnc_client_write_plain(vs); -+ { -+#ifdef CONFIG_VNC_WS -+ if (vs->encode_ws) { -+ vnc_client_write_ws(vs); -+ } else -+#endif /* CONFIG_VNC_WS */ -+ { -+ vnc_client_write_plain(vs); -+ } -+ } - } - - void vnc_client_write(void *opaque) -@@ -1201,7 +1219,11 @@ - VncState *vs = opaque; - - vnc_lock_output(vs); -- if (vs->output.offset) { -+ if (vs->output.offset -+#ifdef CONFIG_VNC_WS -+ || vs->ws_output.offset -+#endif -+ ) { - vnc_client_write_locked(opaque); - } else if (vs->csock != -1) { - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); -@@ -1295,7 +1317,21 @@ - ret = vnc_client_read_sasl(vs); - else - #endif /* CONFIG_VNC_SASL */ -+#ifdef CONFIG_VNC_WS -+ if (vs->encode_ws) { -+ ret = vnc_client_read_ws(vs); -+ if (ret == -1) { -+ vnc_disconnect_start(vs); -+ return; -+ } else if (ret == -2) { -+ vnc_client_error(vs); -+ return; -+ } -+ } else -+#endif /* CONFIG_VNC_WS */ -+ { - ret = vnc_client_read_plain(vs); -+ } - if (!ret) { - if (vs->csock == -1) - vnc_disconnect_finish(vs); -@@ -1313,8 +1349,7 @@ - } - - if (!ret) { -- memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len)); -- vs->input.offset -= len; -+ buffer_advance(&vs->input, len); - } else { - vs->read_handler_expect = ret; - } -@@ -1367,7 +1402,11 @@ - void vnc_flush(VncState *vs) - { - vnc_lock_output(vs); -- if (vs->csock != -1 && vs->output.offset) { -+ if (vs->csock != -1 && (vs->output.offset -+#ifdef CONFIG_VNC_WS -+ || vs->ws_output.offset -+#endif -+ )) { - vnc_client_write_locked(vs); - } - vnc_unlock_output(vs); -@@ -2657,7 +2696,7 @@ - } - } - --static void vnc_connect(VncDisplay *vd, int csock, int skipauth) -+static void vnc_connect(VncDisplay *vd, int csock, int skipauth, bool websocket) - { - VncState *vs = g_malloc0(sizeof(VncState)); - int i; -@@ -2684,13 +2723,34 @@ - VNC_DEBUG("New client on socket %d\n", csock); - dcl->idle = 0; - socket_set_nonblock(vs->csock); -- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); -+#ifdef CONFIG_VNC_WS -+ if (websocket) { -+ vs->websocket = 1; -+ qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs); -+ } else -+#endif /* CONFIG_VNC_WS */ -+ { -+ qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); -+ } - - vnc_client_cache_addr(vs); - vnc_qmp_event(vs, QEVENT_VNC_CONNECTED); - vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING); - - vs->vd = vd; -+ -+#ifdef CONFIG_VNC_WS -+ if (!vs->websocket) -+#endif -+ { -+ vnc_init_state(vs); -+ } -+} -+ -+void vnc_init_state(VncState *vs) -+{ -+ VncDisplay *vd = vs->vd; -+ - vs->ds = vd->ds; - vs->last_x = -1; - vs->last_y = -1; -@@ -2722,21 +2782,41 @@ - /* vs might be free()ed here */ - } - --static void vnc_listen_read(void *opaque) -+static void vnc_listen_read(void *opaque, bool websocket) - { - VncDisplay *vs = opaque; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(addr); -+ int csock; - - /* Catch-up */ - vga_hw_update(); -+#ifdef CONFIG_VNC_WS -+ if (websocket) { -+ csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen); -+ } else -+#endif /* CONFIG_VNC_WS */ -+ { -+ csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); -+ } - -- int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); - if (csock != -1) { -- vnc_connect(vs, csock, 0); -+ vnc_connect(vs, csock, 0, websocket); - } - } - -+static void vnc_listen_regular_read(void *opaque) -+{ -+ vnc_listen_read(opaque, 0); -+} -+ -+#ifdef CONFIG_VNC_WS -+static void vnc_listen_websocket_read(void *opaque) -+{ -+ vnc_listen_read(opaque, 1); -+} -+#endif /* CONFIG_VNC_WS */ -+ - void vnc_display_init(DisplayState *ds) - { - VncDisplay *vs = g_malloc0(sizeof(*vs)); -@@ -2748,6 +2828,9 @@ - vnc_display = vs; - - vs->lsock = -1; -+#ifdef CONFIG_VNC_WS -+ vs->lwebsock = -1; -+#endif - - vs->ds = ds; - QTAILQ_INIT(&vs->clients); -@@ -2789,6 +2872,15 @@ - close(vs->lsock); - vs->lsock = -1; - } -+#ifdef CONFIG_VNC_WS -+ g_free(vs->ws_display); -+ vs->ws_display = NULL; -+ if (vs->lwebsock != -1) { -+ qemu_set_fd_handler2(vs->lwebsock, NULL, NULL, NULL, NULL); -+ close(vs->lwebsock); -+ vs->lwebsock = -1; -+ } -+#endif /* CONFIG_VNC_WS */ - vs->auth = VNC_AUTH_INVALID; - #ifdef CONFIG_VNC_TLS - vs->subauth = VNC_AUTH_INVALID; -@@ -2910,6 +3002,36 @@ - } else if (strncmp(options, "sasl", 4) == 0) { - sasl = 1; /* Require SASL auth */ - #endif -+#ifdef CONFIG_VNC_WS -+ } else if (strncmp(options, "websocket", 9) == 0) { -+ char *start, *end; -+ vs->websocket = 1; -+ -+ /* Check for 'websocket=<port>' */ -+ start = strchr(options, '='); -+ end = strchr(options, ','); -+ if (start && (!end || (start < end))) { -+ int len = end ? end-(start+1) : strlen(start+1); -+ if (len < 6) { -+ /* extract the host specification from display */ -+ char *host = NULL, *port = NULL, *host_end = NULL; -+ port = g_strndup(start + 1, len); -+ -+ /* ipv6 hosts have colons */ -+ end = strchr(display, ','); -+ host_end = g_strrstr_len(display, end - display, ":"); -+ -+ if (host_end) { -+ host = g_strndup(display, host_end - display + 1); -+ } else { -+ host = g_strndup(":", 1); -+ } -+ vs->ws_display = g_strconcat(host, port, NULL); -+ g_free(host); -+ g_free(port); -+ } -+ } -+#endif /* CONFIG_VNC_WS */ - #ifdef CONFIG_VNC_TLS - } else if (strncmp(options, "tls", 3) == 0) { - tls = 1; /* Require TLS */ -@@ -3068,6 +3190,9 @@ - /* connect to viewer */ - int csock; - vs->lsock = -1; -+#ifdef CONFIG_VNC_WS -+ vs->lwebsock = -1; -+#endif - if (strncmp(display, "unix:", 5) == 0) { - csock = unix_connect(display+5, errp); - } else { -@@ -3076,7 +3201,7 @@ - if (csock < 0) { - goto fail; - } -- vnc_connect(vs, csock, 0); -+ vnc_connect(vs, csock, 0, 0); - } else { - /* listen for connects */ - char *dpy; -@@ -3087,25 +3212,54 @@ - } else { - vs->lsock = inet_listen(display, dpy, 256, - SOCK_STREAM, 5900, errp); -+ if (vs->lsock < 0) { -+ g_free(dpy); -+ goto fail; -+ } -+#ifdef CONFIG_VNC_WS -+ if (vs->websocket) { -+ if (vs->ws_display) { -+ vs->lwebsock = inet_listen(vs->ws_display, NULL, 256, -+ SOCK_STREAM, 0, errp); -+ } else { -+ vs->lwebsock = inet_listen(vs->display, NULL, 256, -+ SOCK_STREAM, 5700, errp); -+ } -+ -+ if (vs->lwebsock < 0) { -+ if (vs->lsock) { -+ close(vs->lsock); -+ vs->lsock = -1; -+ } -+ g_free(dpy); -+ goto fail; -+ } -+ } -+#endif /* CONFIG_VNC_WS */ - } -- if (vs->lsock < 0) { -- g_free(dpy); -- goto fail; -- } - g_free(vs->display); - vs->display = dpy; -- qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs); -+ qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_regular_read, NULL, vs); -+#ifdef CONFIG_VNC_WS -+ if (vs->websocket) { -+ qemu_set_fd_handler2(vs->lwebsock, NULL, vnc_listen_websocket_read, NULL, vs); -+ } -+#endif - } - return; - - fail: - g_free(vs->display); - vs->display = NULL; -+#ifdef CONFIG_VNC_WS -+ g_free(vs->ws_display); -+ vs->ws_display = NULL; -+#endif /* CONFIG_VNC_WS */ - } - - void vnc_display_add_client(DisplayState *ds, int csock, int skipauth) - { - VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; - -- vnc_connect(vs, csock, skipauth); -+ vnc_connect(vs, csock, skipauth, 0); - } ---- xen-4.3.0.orig/tools/qemu-xen/ui/vnc.h -+++ xen-4.3.0/tools/qemu-xen/ui/vnc.h -@@ -99,6 +99,9 @@ - #ifdef CONFIG_VNC_SASL - #include "vnc-auth-sasl.h" - #endif -+#ifdef CONFIG_VNC_WS -+#include "vnc-ws.h" -+#endif - - struct VncRectStat - { -@@ -142,6 +145,11 @@ - QEMUTimer *timer; - int timer_interval; - int lsock; -+#ifdef CONFIG_VNC_WS -+ int lwebsock; -+ bool websocket; -+ char *ws_display; -+#endif - DisplayState *ds; - kbd_layout_t *kbd_layout; - int lock_key_sync; -@@ -269,11 +277,19 @@ - #ifdef CONFIG_VNC_SASL - VncStateSASL sasl; - #endif -+#ifdef CONFIG_VNC_WS -+ bool encode_ws; -+ bool websocket; -+#endif - - QObject *info; - - Buffer output; - Buffer input; -+#ifdef CONFIG_VNC_WS -+ Buffer ws_input; -+ Buffer ws_output; -+#endif - /* current output mode information */ - VncWritePixels *write_pixels; - PixelFormat client_pf; -@@ -493,6 +509,8 @@ - void vnc_write_u8(VncState *vs, uint8_t value); - void vnc_flush(VncState *vs); - void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting); -+void vnc_disconnect_finish(VncState *vs); -+void vnc_init_state(VncState *vs); - - - /* Buffer I/O functions */ -@@ -510,7 +528,8 @@ - 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); -+uint8_t *buffer_end(Buffer *buffer); - - /* Misc helpers */ - |