aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Pitcock <nenolod@dereferenced.org>2013-07-01 14:38:20 -0500
committerWilliam Pitcock <nenolod@dereferenced.org>2013-07-01 14:38:20 -0500
commite095f1bd0bb9ff6dc8f1ceeff2277537bc3de153 (patch)
treed603277ae92aed3ac39fe16ca3043c6c2f9a7ced
parent448e4822bbf8a2b4aa8b8f8d8153a2a0b4e0efda (diff)
downloadaports-e095f1bd0bb9ff6dc8f1ceeff2277537bc3de153.tar.bz2
aports-e095f1bd0bb9ff6dc8f1ceeff2277537bc3de153.tar.xz
main/xen: splice in websockets support on qemu-xen device-model
-rw-r--r--main/xen/APKBUILD8
-rw-r--r--main/xen/qemu-xen-websocket.patch910
-rw-r--r--main/xen/use-xen-qemu-upstream.patch10
3 files changed, 926 insertions, 2 deletions
diff --git a/main/xen/APKBUILD b/main/xen/APKBUILD
index a2b82db3eb..e787912599 100644
--- a/main/xen/APKBUILD
+++ b/main/xen/APKBUILD
@@ -3,7 +3,7 @@
# Maintainer: William Pitcock <nenolod@dereferenced.org>
pkgname=xen
pkgver=4.2.2
-pkgrel=6
+pkgrel=7
pkgdesc="Xen hypervisor"
url="http://www.xen.org/"
arch="x86 x86_64"
@@ -11,7 +11,7 @@ license="GPL"
depends="syslinux bash screen iproute2 logrotate perl"
depends_dev="openssl-dev python-dev e2fsprogs-dev gettext zlib-dev ncurses-dev
libiconv-dev dev86 texinfo perl iasl pciutils-dev glib-dev yajl-dev
- spice-dev"
+ spice-dev gnutls-dev"
makedepends="$depends_dev"
install=""
subpackages="$pkgname-doc $pkgname-dev $pkgname-libs $pkgname-hypervisor $pkgname-xend"
@@ -35,6 +35,7 @@ source="http://bits.xensource.com/oss-xen/release/$pkgver/$pkgname-$pkgver.tar.g
xsa58-4.2.patch
fix-pod2man-choking.patch
+ qemu-xen-websocket.patch
xenstored.initd
xenstored.confd
@@ -166,6 +167,7 @@ e70b9128ffc2175cea314a533a7d8457 xsa56.patch
7475158130474ee062a4eb878259af61 xsa57.patch
7de2cd11c10d6a554f3c81e0688c38b7 xsa58-4.2.patch
c1d1a415415b0192e5dae9032962bf61 fix-pod2man-choking.patch
+b72ee3a59d4e4e4f9816c03e0128ccc1 qemu-xen-websocket.patch
95d8af17bf844d41a015ff32aae51ba1 xenstored.initd
b017ccdd5e1c27bbf1513e3569d4ff07 xenstored.confd
ed262f15fb880badb53575539468646c xenconsoled.initd
@@ -195,6 +197,7 @@ a691c5f5332a42c0d38ddb4dc037eb902f01ba31033b64c47d02909a8de0257d xsa56.patch
b6a5106848541972519cc529859d9ff3083c79367276c7031560fa4ce6f9f770 xsa57.patch
194d6610fc38b767d643e5d58a1268f45921fb35e309b47aca6a388b861311c2 xsa58-4.2.patch
b4e7d43364a06b2cb04527db3e9567524bc489fef475709fd8493ebf1e62406d fix-pod2man-choking.patch
+1b658baa846a472bceb33457e6f2414711eeaa79819f9492ba978c3daf00dc8f qemu-xen-websocket.patch
81d335946c81311c86e2f2112b773a568a5a530c0db9802b2fe559e71bb8b381 xenstored.initd
ea9171e71ab3d33061979bcf3bb737156192aa4b0be4d1234438ced75b6fdef3 xenstored.confd
93bea2eb90ea1b4628854c8141dd351bbd1fbc5959b12795447ea933ad025f01 xenconsoled.initd
@@ -224,6 +227,7 @@ b4f43095163146a29ae258575bb03bd45f5a315d3cca7434a0b88c18eb1b6e1cf17ef13b4ac428a0
5ccc1654d9f0270485495f9fc913e41663ddbda602ffe049e0a9c3247c6246690b7ec4165482f96921c5253a2a5205ca384048339996e611c07ab60a6a75cf6a xsa57.patch
60813c01f6bb909da8748919df4d0ffa923baf4b7b55287e0bec3389fb83020158225182e112941c9e126b4df57e7b8724f2a69d0c1fa9ce3b37c0bdf1a49da4 xsa58-4.2.patch
ffb1113fcec0853b690c177655c7d1136388efdebf0d7f625b80481b98eadd3e9ef461442ced53e11acf0e347800a2b0a41e18b05065b5d04bffdd8a4e127cec fix-pod2man-choking.patch
+a48337c7f687e6d2dff400e99e2f544361c5dcaf6a4c745892603c73087f7f9be48eccadf77baee3e106c01b749b335646ccb10b29272b2f5ca681d2514228f6 qemu-xen-websocket.patch
792b062e8a16a2efd3cb4662d379d1500527f2a7ca9228d7831c2bd34f3b9141df949153ea05463a7758c3e3dd9a4182492ad5505fa38e298ecf8c99db77b4ee xenstored.initd
100cf4112f401f45c1e4e885a5074698c484b40521262f6268fad286498e95f4c51e746f0e94eb43a590bb8e813a397bb53801ccacebec9541020799d8d70514 xenstored.confd
12f981b2459c65d66e67ec0b32d0d19b95a029bc54c2a79138cfe488d3524a22e51860f755abfe25ddcdaf1b27f2ded59b6e350b9d5f8791193d00e2d3673137 xenconsoled.initd
diff --git a/main/xen/qemu-xen-websocket.patch b/main/xen/qemu-xen-websocket.patch
new file mode 100644
index 0000000000..9d1b2e6dad
--- /dev/null
+++ b/main/xen/qemu-xen-websocket.patch
@@ -0,0 +1,910 @@
+--- xen-4.2.2.orig/tools/Makefile
++++ xen-4.2.2/tools/Makefile
+@@ -202,6 +202,7 @@
+ --docdir=$(PREFIX)/share/doc \
+ --sysconfdir=/etc/qemu \
+ --disable-kvm \
++ --enable-vnc-ws \
+ --python=$(PYTHON) \
+ $(IOEMU_CONFIGURE_CROSS); \
+ $(MAKE) all
+--- xen-4.2.2.orig/tools/qemu-xen/Makefile.objs
++++ xen-4.2.2/tools/qemu-xen/Makefile.objs
+@@ -149,6 +149,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
+ ifdef CONFIG_VNC_THREAD
+ vnc-obj-y += vnc-jobs-async.o
+ else
+--- xen-4.2.2.orig/tools/qemu-xen/configure
++++ xen-4.2.2/tools/qemu-xen/configure
+@@ -124,6 +124,7 @@
+ vnc_sasl=""
+ vnc_jpeg=""
+ vnc_png=""
++vnc_ws=""
+ vnc_thread="no"
+ xen=""
+ xen_ctrl_version=""
+@@ -638,6 +639,10 @@
+ ;;
+ --enable-vnc-thread) vnc_thread="yes"
+ ;;
++ --disable-vnc-ws) vnc_ws="no"
++ ;;
++ --enable-vnc-ws) vnc_ws="yes"
++ ;;
+ --disable-slirp) slirp="no"
+ ;;
+ --disable-uuid) uuid="no"
+@@ -1008,6 +1013,8 @@
+ echo " --enable-vnc-png enable PNG compression for VNC server"
+ echo " --disable-vnc-thread disable threaded VNC server"
+ echo " --enable-vnc-thread enable threaded 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"
+@@ -1554,8 +1561,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; }
+@@ -1563,13 +1570,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
+
+@@ -2864,6 +2880,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"
+ echo "VNC thread $vnc_thread"
+ fi
+ if test -n "$sparc_cpu"; then
+@@ -3053,6 +3070,10 @@
+ fi
+ if test "$vnc_thread" = "yes" ; then
+ echo "CONFIG_VNC_THREAD=y" >> $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.2.2.orig/tools/qemu-xen/qemu-options.hx
++++ xen-4.2.2/tools/qemu-xen/qemu-options.hx
+@@ -976,6 +976,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.
+--- /dev/null
++++ xen-4.2.2/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.2.2/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.2.2.orig/tools/qemu-xen/ui/vnc.c
++++ xen-4.2.2/tools/qemu-xen/ui/vnc.c
+@@ -391,7 +391,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);
+
+@@ -479,6 +478,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;
+@@ -1002,7 +1008,7 @@
+ vs->csock = -1;
+ }
+
+-static void vnc_disconnect_finish(VncState *vs)
++void vnc_disconnect_finish(VncState *vs)
+ {
+ int i;
+
+@@ -1013,6 +1019,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);
+
+@@ -1150,8 +1160,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);
+@@ -1177,7 +1186,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)
+@@ -1185,7 +1203,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);
+@@ -1273,7 +1295,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);
+@@ -1291,8 +1327,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;
+ }
+@@ -1345,7 +1380,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);
+@@ -2525,7 +2564,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;
+@@ -2552,12 +2591,33 @@
+ 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);
+
+ 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;
+@@ -2590,21 +2650,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));
+@@ -2616,6 +2696,9 @@
+ vnc_display = vs;
+
+ vs->lsock = -1;
++#ifdef CONFIG_VNC_WS
++ vs->lwebsock = -1;
++#endif
+
+ vs->ds = ds;
+ QTAILQ_INIT(&vs->clients);
+@@ -2659,6 +2742,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;
+@@ -2769,6 +2861,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 */
+@@ -2931,7 +3053,10 @@
+ } else {
+ int csock = vs->lsock;
+ vs->lsock = -1;
+- vnc_connect(vs, csock, 0);
++#ifdef CONFIG_VNC_WS
++ vs->lwebsock = -1;
++#endif
++ vnc_connect(vs, csock, 0, 0);
+ }
+ return 0;
+
+@@ -2944,6 +3069,30 @@
+ vs->lsock = unix_listen(display+5, dpy+5, 256-5);
+ } else {
+ vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
++ if (-1 == vs->lsock) {
++ 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);
++ } else {
++ vs->lwebsock = inet_listen(vs->display, NULL, 256,
++ SOCK_STREAM, 5700);
++ }
++
++ if (vs->lwebsock < 0) {
++ if (vs->lsock) {
++ close(vs->lsock);
++ vs->lsock = -1;
++ }
++ g_free(dpy);
++ goto fail;
++ }
++ }
++#endif /* CONFIG_VNC_WS */
+ }
+ if (-1 == vs->lsock) {
+ g_free(dpy);
+@@ -2954,11 +3103,20 @@
+ }
+ }
+ return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
++
++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 */
++ return -1;
+ }
+
+ void vnc_display_add_client(DisplayState *ds, int csock, int skipauth)
+ {
+ VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+
+- return vnc_connect(vs, csock, skipauth);
++ return vnc_connect(vs, csock, skipauth, 0);
+ }
+--- xen-4.2.2.orig/tools/qemu-xen/ui/vnc.h
++++ xen-4.2.2/tools/qemu-xen/ui/vnc.h
+@@ -101,6 +101,9 @@
+ #ifdef CONFIG_VNC_SASL
+ #include "vnc-auth-sasl.h"
+ #endif
++#ifdef CONFIG_VNC_WS
++#include "vnc-ws.h"
++#endif
+
+ struct VncRectStat
+ {
+@@ -128,6 +131,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;
+@@ -265,11 +273,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;
+ DisplaySurface clientds;
+@@ -489,6 +505,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 */
+@@ -507,10 +525,11 @@
+ /* Buffer management */
+ void buffer_reserve(Buffer *buffer, size_t len);
+ int buffer_empty(Buffer *buffer);
+-uint8_t *buffer_end(Buffer *buffer);
+ 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 */
diff --git a/main/xen/use-xen-qemu-upstream.patch b/main/xen/use-xen-qemu-upstream.patch
new file mode 100644
index 0000000000..6525a3421e
--- /dev/null
+++ b/main/xen/use-xen-qemu-upstream.patch
@@ -0,0 +1,10 @@
+--- xen-4.2.2.orig/tools/Makefile
++++ xen-4.2.2/tools/Makefile
+@@ -202,6 +202,7 @@
+ --docdir=$(PREFIX)/share/doc \
+ --sysconfdir=/etc/qemu \
+ --disable-kvm \
++ --enable-vnc-ws \
+ --python=$(PYTHON) \
+ $(IOEMU_CONFIGURE_CROSS); \
+ $(MAKE) all