Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 340e01248478ba8b78a6d4d1809b1eff > files > 225

kvm-83-270.el5_11.src.rpm

From d34fd47b7d35a613ed95b0c0db6f5444da31fbc5 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 16 Apr 2009 17:27:02 +0200
Subject: [PATCH 05/14] Support multiple VNC clients (re-added)

On 04/16/09 14:31, Gerd Hoffmann wrote:
>   Hi,
>
> This is a backport of the multiple vnc client patch from upstream qemu.
>
> Fixes bug 490344.
>
> cheers,
> Gerd

Updated patch, one screen corruption bug fixed.

cheers,
   Gerd

>From 315865922b7a6259915ab13cc621bf2a4945b64e Mon Sep 17 00:00:00 2001
From: aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
Date: Mon, 16 Feb 2009 14:59:30 +0000
Subject: [PATCH] Support multiple VNC clients (Brian Kress)

Change structure associated with a display from VncState to a new structure
VncDisplay. Remove client specific fields from VncDisplay. Remove display
specific fields from VncState. Maintain a linked list of VncStates per
VncDisplay structure, update as necessary. When updates/resizes/copies come in
from the hardware, dispatch to all clients.

Signed-off-by: Brian Kress <kressb@moose.net>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6621 c046a42c-6fe2-441c-8c8c-71466251a162

Backported required some non-trivial adaptions due to the
DisplayState reorganization patches not being in the rhel-5
code base.

[ehabkost: Added again now that the qemu_realloc() and displaystate
           initialization patches are being included too]

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
RH-Upstream-status: applied(qemu/trunk)
Message-ID: <49E74E46.1060107@redhat.com>
Depends: <20090518212210.GN2079@blackpad>
Obsoletes: <49E72530.1000402@redhat.com>
Acked-by: Eduardo Habkost <ehabkost@redhat.com>
Acked-by: Zachary Amsden <zamsden@redhat.com>
Acked-by: Juan Quintela <quintela@redhat.com>
Bugzilla: 503793
---
 qemu/vnc.c |  409 ++++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 232 insertions(+), 177 deletions(-)

diff --git a/qemu/vnc.c b/qemu/vnc.c
index a455614..eca5d4d 100644
--- a/qemu/vnc.c
+++ b/qemu/vnc.c
@@ -117,12 +117,36 @@ enum {
 
 #endif /* CONFIG_VNC_TLS */
 
+typedef struct VncDisplay VncDisplay;
+
+struct VncDisplay
+{
+    int lsock;
+    DisplayState *ds;
+    VncState *clients;
+    kbd_layout_t *kbd_layout;
+
+    char *display;
+    char *password;
+    int auth;
+#ifdef CONFIG_VNC_TLS
+    int subauth;
+    int x509verify;
+
+    char *x509cacert;
+    char *x509cacrl;
+    char *x509cert;
+    char *x509key;
+#endif
+    gcry_cipher_hd_t des_cipher;
+};
+
 struct VncState
 {
     QEMUTimer *timer;
-    int lsock;
     int csock;
     DisplayState *ds;
+    VncDisplay *vd;
     int need_update;
     int width;
     int height;
@@ -133,6 +157,7 @@ struct VncState
     int has_hextile;
     int has_pointer_type_change;
     int has_WMVi;
+    int has_copyrect;
     int absolute;
     int last_x;
     int last_y;
@@ -140,18 +165,6 @@ struct VncState
     int major;
     int minor;
 
-    char *display;
-    char *password;
-    int auth;
-#ifdef CONFIG_VNC_TLS
-    int subauth;
-    int x509verify;
-
-    char *x509cacert;
-    char *x509cacrl;
-    char *x509cert;
-    char *x509key;
-#endif
     char challenge[VNC_AUTH_CHALLENGE_SIZE];
 
 #ifdef CONFIG_VNC_TLS
@@ -161,7 +174,6 @@ struct VncState
 
     Buffer output;
     Buffer input;
-    kbd_layout_t *kbd_layout;
     /* current output mode information */
     VncWritePixels *write_pixels;
     VncSendHextileTile *send_hextile_tile;
@@ -178,21 +190,21 @@ struct VncState
     /* input */
     uint8_t modifiers_state[256];
 
-    gcry_cipher_hd_t des_cipher;
+    VncState *next;
 };
 
-static VncState *vnc_state; /* needed for info vnc */
+static VncDisplay *vnc_display; /* needed for info vnc */
 
 void do_info_vnc(void)
 {
-    if (vnc_state == NULL || vnc_state->display == NULL)
+    if (vnc_display == NULL || vnc_display->display == NULL)
 	term_printf("VNC server disabled\n");
     else {
 	term_printf("VNC server active on: ");
-	term_print_filename(vnc_state->display);
+	term_print_filename(vnc_display->display);
 	term_printf("\n");
 
-	if (vnc_state->csock == -1)
+	if (vnc_display->clients == NULL)
 	    term_printf("No client connected\n");
 	else
 	    term_printf("Client connected\n");
@@ -215,7 +227,7 @@ static void vnc_flush(VncState *vs);
 static void vnc_update_client(void *opaque);
 static void vnc_client_read(void *opaque);
 
-static void vnc_colordepth(DisplayState *ds, int depth);
+static void vnc_colordepth(VncState *vs, int depth);
 
 static inline void vnc_set_bit(uint32_t *d, int k)
 {
@@ -258,9 +270,8 @@ static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
     return 0;
 }
 
-static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+static void vnc_update(VncState *vs, int x, int y, int w, int h)
 {
-    VncState *vs = ds->opaque;
     int i;
 
     h += y;
@@ -282,6 +293,17 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
 	    vnc_set_bit(vs->dirty_row[y], (x + i) / 16);
 }
 
+static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs = vd->clients;
+
+    while (vs != NULL) {
+        vnc_update(vs, x, y, w, h);
+        vs = vs->next;
+    }
+}
+
 static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
 				   int32_t encoding)
 {
@@ -293,35 +315,23 @@ static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
     vnc_write_s32(vs, encoding);
 }
 
-static void vnc_dpy_resize(DisplayState *ds, int w, int h)
+static void vnc_resize(VncState *vs, int w, int h)
 {
-    int size_changed;
-    VncState *vs = ds->opaque;
-
-    ds->data = qemu_realloc(ds->data, w * h * vs->depth);
     vs->old_data = qemu_realloc(vs->old_data, w * h * vs->depth);
 
-    if (ds->data == NULL || vs->old_data == NULL) {
+    if (vs->old_data == NULL) {
 	fprintf(stderr, "vnc: memory allocation failed\n");
 	exit(1);
     }
 
-    if (ds->depth != vs->depth * 8) {
-        ds->depth = vs->depth * 8;
-        console_color_init(ds);
-    }
-    size_changed = ds->width != w || ds->height != h;
-    ds->width = w;
-    ds->height = h;
-    ds->linesize = w * vs->depth;
-    if (size_changed) {
-        vs->width = ds->width;
-        vs->height = ds->height;
+    if (vs->width != w || vs->height != h) {
+        vs->width = w;
+        vs->height = h;
         if (vs->csock != -1 && vs->has_resize) {
             vnc_write_u8(vs, 0);  /* msg id */
             vnc_write_u8(vs, 0);
             vnc_write_u16(vs, 1); /* number of rects */
-            vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223);
+            vnc_framebuffer_update(vs, 0, 0, vs->width, vs->height, -223);
             vnc_flush(vs);
         }
     }
@@ -330,6 +340,26 @@ static void vnc_dpy_resize(DisplayState *ds, int w, int h)
     memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
 }
 
+static void vnc_dpy_resize(DisplayState *ds, int w, int h)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs = vd->clients;
+
+    ds->width = w;
+    ds->height = h;
+    ds->linesize = w * ds->depth/8;
+    ds->data = qemu_realloc(ds->data, ds->linesize * ds->height);
+    if (ds->data == NULL) {
+	fprintf(stderr, "vnc: memory allocation failed\n");
+	exit(1);
+    }
+
+    while (vs != NULL) {
+        vnc_resize(vs, w, h);
+        vs = vs->next;
+    }
+}
+
 /* fastest code */
 static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
 {
@@ -494,38 +524,35 @@ static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
 	    send_framebuffer_update_raw(vs, x, y, w, h);
 }
 
-static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+static void vnc_copy_data(uint8_t *data, int pitch, int depth,
+                          int src_x, int src_y, int dst_x, int dst_y, int w, int h)
 {
     int src, dst;
     uint8_t *src_row;
     uint8_t *dst_row;
-    char *old_row;
     int y = 0;
-    int pitch = ds_get_linesize(ds);
-    VncState *vs = ds->opaque;
-
-    vnc_update_client(vs);
+    int p = pitch;
 
     if (dst_y > src_y) {
 	y = h - 1;
-	pitch = -pitch;
+	p = -p;
     }
 
-    src = (ds_get_linesize(ds) * (src_y + y) + vs->depth * src_x);
-    dst = (ds_get_linesize(ds) * (dst_y + y) + vs->depth * dst_x);
+    src = (pitch * (src_y + y) + depth * src_x);
+    dst = (pitch * (dst_y + y) + depth * dst_x);
 
-    src_row = ds_get_data(ds) + src;
-    dst_row = ds_get_data(ds) + dst;
-    old_row = vs->old_data + dst;
+    src_row = data + src;
+    dst_row = data + dst;
 
     for (y = 0; y < h; y++) {
-	memmove(old_row, src_row, w * vs->depth);
-	memmove(dst_row, src_row, w * vs->depth);
-	src_row += pitch;
-	dst_row += pitch;
-	old_row += pitch;
+	memmove(dst_row, src_row, w * depth);
+	src_row += p;
+	dst_row += p;
     }
+}
 
+static void vnc_copy_msg(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
     vnc_write_u8(vs, 0);  /* msg id */
     vnc_write_u8(vs, 0);
     vnc_write_u16(vs, 1); /* number of rects */
@@ -535,6 +562,29 @@ static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_
     vnc_flush(vs);
 }
 
+static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
+{
+    VncDisplay *vd = ds->opaque;
+    VncState *vs;
+
+    for (vs = vd->clients; vs != NULL; vs = vs->next) {
+        if (vs->has_copyrect)
+            vnc_update_client(vs);
+    }
+
+    vnc_copy_data(ds->data, ds->linesize, ds->depth / 8,
+                  src_x, src_y, dst_x, dst_y, w, h);
+    for (vs = vd->clients; vs != NULL; vs = vs->next) {
+        if (vs->has_copyrect) {
+            vnc_copy_data((uint8_t*)vs->old_data, vs->width * vs->depth, vs->depth,
+                          src_x, src_y, dst_x, dst_y, w, h);
+            vnc_copy_msg(vs, src_x, src_y, dst_x, dst_y, w, h);
+        } else {
+            vnc_update(vs, dst_x, dst_y, w, h);
+        }
+    }
+}
+
 static int find_dirty_height(VncState *vs, int y, int last_x, int x)
 {
     int h;
@@ -646,14 +696,6 @@ static void vnc_update_client(void *opaque)
 
 }
 
-static int vnc_listen_poll(void *opaque)
-{
-    VncState *vs = opaque;
-    if (vs->csock == -1)
-	return 1;
-    return 0;
-}
-
 static void buffer_reserve(Buffer *buffer, size_t len)
 {
     if ((buffer->capacity - buffer->offset) < len) {
@@ -676,11 +718,6 @@ static uint8_t *buffer_end(Buffer *buffer)
     return buffer->buffer + buffer->offset;
 }
 
-static void buffer_reset(Buffer *buffer)
-{
-	buffer->offset = 0;
-}
-
 static void buffer_append(Buffer *buffer, const void *data, size_t len)
 {
     memcpy(buffer->buffer + buffer->offset, data, len);
@@ -771,21 +808,38 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 	VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0);
 	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
 	closesocket(vs->csock);
-	vs->csock = -1;
-	vs->ds->idle = 1;
-	buffer_reset(&vs->input);
-	buffer_reset(&vs->output);
-	vs->need_update = 0;
+        qemu_del_timer(vs->timer);
+        qemu_free_timer(vs->timer);
+        if (vs->input.buffer)
+            qemu_free(vs->input.buffer);
+        if (vs->output.buffer)
+            qemu_free(vs->output.buffer);
 #ifdef CONFIG_VNC_TLS
 	if (vs->tls_session) {
 	    gnutls_deinit(vs->tls_session);
 	    vs->tls_session = NULL;
 	}
-	vs->wiremode = VNC_WIREMODE_CLEAR;
 #endif /* CONFIG_VNC_TLS */
         audio_del(vs);
-        if (vs->display)
-            term_printf_async(VNC_ASYNC_EVENT, "VNC: Closing down connection %s\n", vs->display);
+        if (vs->vd->display)
+            term_printf_async(VNC_ASYNC_EVENT, "VNC: Closing down connection %s\n", vs->vd->display);
+
+        VncState *p, *parent = NULL;
+        for (p = vs->vd->clients; p != NULL; p = p->next) {
+            if (p == vs) {
+                if (parent)
+                    parent->next = p->next;
+                else
+                    vs->vd->clients = p->next;
+                break;
+            }
+            parent = p;
+        }
+        if (!vs->vd->clients)
+            vs->ds->idle = 1;
+        qemu_free(vs->old_data);
+        qemu_free(vs);
+
 	return 0;
     }
     return ret;
@@ -1050,8 +1104,8 @@ static void reset_keys(VncState *vs)
 
 static void press_key(VncState *vs, int keysym)
 {
-    kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) & 0x7f);
-    kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80);
+    kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f);
+    kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80);
 }
 
 static void do_key_event(VncState *vs, int down, int keycode, int sym)
@@ -1084,12 +1138,12 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
         break;
     }
 
-    if (keycode_is_keypad(vs->kbd_layout, keycode)) {
+    if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
         /* If the numlock state needs to change then simulate an additional
            keypress before sending this one.  This will happen if the user
            toggles numlock away from the VNC window.
         */
-        if (keysym_is_numlock(vs->kbd_layout, sym & 0xFFFF)) {
+        if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
             if (!vs->modifiers_state[0x45]) {
                 vs->modifiers_state[0x45] = 1;
                 press_key(vs, 0xff7f);
@@ -1162,7 +1216,7 @@ static void key_event(VncState *vs, int down, uint32_t sym)
     if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
 	sym = sym - 'A' + 'a';
 
-    keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
+    keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF);
     do_key_event(vs, down, keycode, sym);
 }
 
@@ -1229,8 +1283,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
     vs->has_resize = 0;
     vs->has_pointer_type_change = 0;
     vs->has_WMVi = 0;
+    vs->has_copyrect = 0;
     vs->absolute = -1;
-    vs->ds->dpy_copy = NULL;
 
     for (i = n_encodings - 1; i >= 0; i--) {
 	switch (encodings[i]) {
@@ -1238,7 +1292,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
 	    vs->has_hextile = 0;
 	    break;
 	case 1: /* CopyRect */
-	    vs->ds->dpy_copy = vnc_copy;
+	    vs->has_copyrect = 1;
 	    break;
 	case 5: /* Hextile */
 	    vs->has_hextile = 1;
@@ -1391,14 +1445,14 @@ static void pixel_format_message (VncState *vs) {
     vnc_write(vs, pad, 3);           /* padding */
 }
 
-static void vnc_colordepth(DisplayState *ds, int depth)
+static void vnc_colordepth(VncState *vs, int depth)
 {
     int host_big_endian_flag;
-    struct VncState *vs = ds->opaque;
 
     switch (depth) {
         case 24:
-            if (ds->depth == 32) return;
+            if (vs->ds->depth == 32)
+                return;
             depth = 32;
             break;
         case 15:
@@ -1452,7 +1506,7 @@ static void vnc_colordepth(DisplayState *ds, int depth)
         vnc_write_u8(vs, 0);  /* msg id */
         vnc_write_u8(vs, 0);
         vnc_write_u16(vs, 1); /* number of rects */
-        vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669);
+        vnc_framebuffer_update(vs, 0, 0, vs->ds->width, vs->ds->height, 0x574D5669);
         pixel_format_message(vs);
         vnc_flush(vs);
     } else {
@@ -1675,7 +1729,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
     char key[8];
     gcry_error_t e;
 
-    if (!vs->password || !vs->password[0]) {
+    if (!vs->vd->password || !vs->vd->password[0]) {
 	VNC_DEBUG("No password configured on server");
 	vnc_write_u32(vs, 1); /* Reject auth */
 	if (vs->minor >= 8) {
@@ -1688,7 +1742,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
 	return 0;
     }
 
-    if (gcry_cipher_reset(vs->des_cipher)) {
+    if (gcry_cipher_reset(vs->vd->des_cipher)) {
         VNC_DEBUG("f1\n");
         goto fail;
     }
@@ -1696,16 +1750,16 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
     memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
 
     /* Calculate the expected challenge response */
-    pwlen = strlen(vs->password);
+    pwlen = strlen(vs->vd->password);
     for (i=0; i<sizeof(key); i++)
-        key[i] = i<pwlen ? bitrev(vs->password[i]) : 0;
+        key[i] = i<pwlen ? bitrev(vs->vd->password[i]) : 0;
 
-    if (gcry_cipher_setkey(vs->des_cipher, key, sizeof(key))) {
+    if (gcry_cipher_setkey(vs->vd->des_cipher, key, sizeof(key))) {
         VNC_DEBUG("f2\n");
         goto fail;
     }
     for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8) {
-        if ( (e = gcry_cipher_encrypt(vs->des_cipher, response+j, 8, NULL, 0)) ) {
+        if ( (e = gcry_cipher_encrypt(vs->vd->des_cipher, response+j, 8, NULL, 0)) ) {
             VNC_DEBUG("f3: %s\n", gcry_strerror(e));
             goto fail;
         }
@@ -1807,15 +1861,15 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *v
     gnutls_certificate_credentials_t x509_cred;
     int ret;
 
-    if (!vs->x509cacert) {
+    if (!vs->vd->x509cacert) {
 	VNC_DEBUG("No CA x509 certificate specified\n");
 	return NULL;
     }
-    if (!vs->x509cert) {
+    if (!vs->vd->x509cert) {
 	VNC_DEBUG("No server x509 certificate specified\n");
 	return NULL;
     }
-    if (!vs->x509key) {
+    if (!vs->vd->x509key) {
 	VNC_DEBUG("No server private key specified\n");
 	return NULL;
     }
@@ -1825,7 +1879,7 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *v
 	return NULL;
     }
     if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
-						      vs->x509cacert,
+						      vs->vd->x509cacert,
 						      GNUTLS_X509_FMT_PEM)) < 0) {
 	VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
 	gnutls_certificate_free_credentials(x509_cred);
@@ -1833,17 +1887,17 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *v
     }
 
     if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
-						     vs->x509cert,
-						     vs->x509key,
+						     vs->vd->x509cert,
+						     vs->vd->x509key,
 						     GNUTLS_X509_FMT_PEM)) < 0) {
 	VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
 	gnutls_certificate_free_credentials(x509_cred);
 	return NULL;
     }
 
-    if (vs->x509cacrl) {
+    if (vs->vd->x509cacrl) {
 	if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
-							vs->x509cacrl,
+							vs->vd->x509cacrl,
 							GNUTLS_X509_FMT_PEM)) < 0) {
 	    VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
 	    gnutls_certificate_free_credentials(x509_cred);
@@ -1937,7 +1991,7 @@ static int vnc_validate_certificate(struct VncState *vs)
 
 static int start_auth_vencrypt_subauth(VncState *vs)
 {
-    switch (vs->subauth) {
+    switch (vs->vd->subauth) {
     case VNC_AUTH_VENCRYPT_TLSNONE:
     case VNC_AUTH_VENCRYPT_X509NONE:
        VNC_DEBUG("Accept TLS auth none\n");
@@ -1951,7 +2005,7 @@ static int start_auth_vencrypt_subauth(VncState *vs)
        return start_auth_vnc(vs);
 
     default: /* Should not be possible, but just in case */
-       VNC_DEBUG("Reject auth %d\n", vs->auth);
+       VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
        vnc_write_u8(vs, 1);
        if (vs->minor >= 8) {
            static const char err[] = "Unsupported authentication type";
@@ -1983,7 +2037,7 @@ static int vnc_continue_handshake(struct VncState *vs) {
        return -1;
     }
 
-    if (vs->x509verify) {
+    if (vs->vd->x509verify) {
 	if (vnc_validate_certificate(vs) < 0) {
 	    VNC_DEBUG("Client verification failed\n");
 	    vnc_client_error(vs);
@@ -2008,9 +2062,9 @@ static void vnc_handshake_io(void *opaque) {
 }
 
 #define NEED_X509_AUTH(vs)			      \
-    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
-     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
+    ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
+     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
+     (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
 
 
 static int vnc_start_tls(struct VncState *vs) {
@@ -2074,7 +2128,7 @@ static int vnc_start_tls(struct VncState *vs) {
 		vnc_client_error(vs);
 		return -1;
 	    }
-	    if (vs->x509verify) {
+	    if (vs->vd->x509verify) {
 		VNC_DEBUG("Requesting a client certificate\n");
 		gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
 	    }
@@ -2109,7 +2163,7 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
 {
     int auth = read_u32(data, 0);
 
-    if (auth != vs->subauth) {
+    if (auth != vs->vd->subauth) {
 	VNC_DEBUG("Rejecting auth %d\n", auth);
 	vnc_write_u8(vs, 0); /* Reject auth */
 	vnc_flush(vs);
@@ -2144,10 +2198,10 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
 	vnc_flush(vs);
 	vnc_client_error(vs);
     } else {
-	VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
+	VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
 	vnc_write_u8(vs, 0); /* Accept version */
 	vnc_write_u8(vs, 1); /* Number of sub-auths */
-	vnc_write_u32(vs, vs->subauth); /* The supported auth */
+	vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
 	vnc_flush(vs);
 	vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
     }
@@ -2169,7 +2223,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
 {
     /* We only advertise 1 auth scheme at a time, so client
      * must pick the one we sent. Verify this */
-    if (data[0] != vs->auth) { /* Reject auth */
+    if (data[0] != vs->vd->auth) { /* Reject auth */
        VNC_DEBUG("Reject auth %d\n", (int)data[0]);
        vnc_write_u32(vs, 1);
        if (vs->minor >= 8) {
@@ -2180,7 +2234,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
        vnc_client_error(vs);
     } else { /* Accept requested auth */
        VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
-       switch (vs->auth) {
+       switch (vs->vd->auth) {
        case VNC_AUTH_NONE:
            VNC_DEBUG("Accept auth none\n");
            if (vs->minor >= 8) {
@@ -2201,7 +2255,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
 #endif /* CONFIG_VNC_TLS */
 
        default: /* Should not be possible, but just in case */
-           VNC_DEBUG("Reject auth %d\n", vs->auth);
+           VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
            vnc_write_u8(vs, 1);
            if (vs->minor >= 8) {
                static const char err[] = "Authentication failed";
@@ -2246,26 +2300,26 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
 	vs->minor = 3;
 
     if (vs->minor == 3) {
-	if (vs->auth == VNC_AUTH_NONE) {
+	if (vs->vd->auth == VNC_AUTH_NONE) {
             VNC_DEBUG("Tell client auth none\n");
-            vnc_write_u32(vs, vs->auth);
+            vnc_write_u32(vs, vs->vd->auth);
             vnc_flush(vs);
             vnc_read_when(vs, protocol_client_init, 1);
-       } else if (vs->auth == VNC_AUTH_VNC) {
+       } else if (vs->vd->auth == VNC_AUTH_VNC) {
             VNC_DEBUG("Tell client VNC auth\n");
-            vnc_write_u32(vs, vs->auth);
+            vnc_write_u32(vs, vs->vd->auth);
             vnc_flush(vs);
             start_auth_vnc(vs);
        } else {
-            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
+            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
             vnc_write_u32(vs, VNC_AUTH_INVALID);
             vnc_flush(vs);
             vnc_client_error(vs);
        }
     } else {
-	VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
+	VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
 	vnc_write_u8(vs, 1); /* num auth */
-	vnc_write_u8(vs, vs->auth);
+	vnc_write_u8(vs, vs->vd->auth);
 	vnc_read_when(vs, protocol_client_auth, 1);
 	vnc_flush(vs);
     }
@@ -2273,58 +2327,86 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
     return 0;
 }
 
-static void vnc_connect(VncState *vs)
+static void vnc_connect(VncDisplay *vd, int csock)
 {
+    VncState *vs = qemu_mallocz(sizeof(VncState));
+    vs->csock = csock;
+
     VNC_DEBUG("New client on socket %d\n", vs->csock);
-    vs->ds->idle = 0;
     socket_set_nonblock(vs->csock);
     qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+
+    vs->vd = vd;
+    vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
+    vs->last_x = -1;
+    vs->last_y = -1;
+    vs->as.freq = 44100;
+    vs->as.nchannels = 2;
+    vs->as.fmt = AUD_FMT_S16;
+    vs->as.endianness = 0;
+
+    vs->ds = vd->ds;
+    vs->ds->idle = 0;
+    if (vs->ds->depth != 32) {
+        /*
+         * We allways run with 32bpp internally.
+         * Easiest to handle with multiple clients, and
+         * this is what almost everybody uses anyway.
+         */
+        vs->ds->depth = 32;
+        console_color_init(vs->ds);
+    }
+    vnc_colordepth(vs, vs->ds->depth);
+    if (vs->ds->width && vs->ds->height) {
+        vnc_resize(vs, vs->ds->width, vs->ds->height);
+    } else {
+        vnc_resize(vs, 640, 480);
+    }
+
     vnc_write(vs, "RFB 003.008\n", 12);
     vnc_flush(vs);
     vnc_read_when(vs, protocol_version, 12);
-    memset(vs->old_data, 0, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
+    memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
     memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
     vs->has_resize = 0;
     vs->has_hextile = 0;
     vs->has_WMVi = 0;
-    vs->ds->dpy_copy = NULL;
+    vs->has_copyrect = 0;
     vnc_update_client(vs);
     reset_keys(vs);
+
+    vs->next = vd->clients;
+    vd->clients = vs;
 }
 
 static void vnc_listen_read(void *opaque)
 {
-    VncState *vs = opaque;
+    VncDisplay *vs = opaque;
     struct sockaddr_in addr;
     socklen_t addrlen = sizeof(addr);
 
     /* Catch-up */
     vga_hw_update();
 
-    vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
-    if (vs->csock != -1) {
-        vnc_connect(vs);
+    int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
+    if (csock != -1) {
+        vnc_connect(vs, csock);
     }
 }
 
 void vnc_display_init(DisplayState *ds)
 {
-    VncState *vs;
+    VncDisplay *vs;
 
-    vs = qemu_mallocz(sizeof(VncState));
+    vs = qemu_mallocz(sizeof(VncDisplay));
     if (!vs)
 	exit(1);
 
     ds->opaque = vs;
     ds->idle = 1;
-    vnc_state = vs;
-    vs->display = NULL;
-    vs->password = NULL;
+    vnc_display = vs;
 
     vs->lsock = -1;
-    vs->csock = -1;
-    vs->last_x = -1;
-    vs->last_y = -1;
 
     vs->ds = ds;
 
@@ -2336,20 +2418,10 @@ void vnc_display_init(DisplayState *ds)
     if (!vs->kbd_layout)
 	exit(1);
 
-    vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
-
     vs->ds->data = NULL;
+    vs->ds->dpy_copy = vnc_dpy_copy;
     vs->ds->dpy_update = vnc_dpy_update;
     vs->ds->dpy_resize = vnc_dpy_resize;
-    vs->ds->dpy_refresh = NULL;
-
-    vnc_colordepth(vs->ds, 32);
-    vnc_dpy_resize(vs->ds, 640, 400);
-
-    vs->as.freq = 44100;
-    vs->as.nchannels = 2;
-    vs->as.fmt = AUD_FMT_S16;
-    vs->as.endianness = 0;
 
     if (!gcry_check_version (GCRYPT_VERSION)) {
         fprintf(stderr, "libgcrypt initialization error\n");
@@ -2363,7 +2435,7 @@ void vnc_display_init(DisplayState *ds)
 }
 
 #ifdef CONFIG_VNC_TLS
-static int vnc_set_x509_credential(VncState *vs,
+static int vnc_set_x509_credential(VncDisplay *vs,
 				   const char *certdir,
 				   const char *filename,
 				   char **cred,
@@ -2395,7 +2467,7 @@ static int vnc_set_x509_credential(VncState *vs,
     return 0;
 }
 
-static int vnc_set_x509_credential_dir(VncState *vs,
+static int vnc_set_x509_credential_dir(VncDisplay *vs,
 				       const char *certdir)
 {
     if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
@@ -2421,7 +2493,7 @@ static int vnc_set_x509_credential_dir(VncState *vs,
 
 void vnc_display_close(DisplayState *ds)
 {
-    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
 
     if (vs->display) {
 	qemu_free(vs->display);
@@ -2432,34 +2504,16 @@ void vnc_display_close(DisplayState *ds)
 	close(vs->lsock);
 	vs->lsock = -1;
     }
-    if (vs->csock != -1) {
-	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
-	closesocket(vs->csock);
-	vs->csock = -1;
-	buffer_reset(&vs->input);
-	buffer_reset(&vs->output);
-	vs->need_update = 0;
-#ifdef CONFIG_VNC_TLS
-	if (vs->tls_session) {
-	    gnutls_deinit(vs->tls_session);
-	    vs->tls_session = NULL;
-	}
-	vs->wiremode = VNC_WIREMODE_CLEAR;
-#endif /* CONFIG_VNC_TLS */
-    }
     vs->auth = VNC_AUTH_INVALID;
 #ifdef CONFIG_VNC_TLS
     vs->subauth = VNC_AUTH_INVALID;
     vs->x509verify = 0;
 #endif
-    audio_del(vs);
-    if (vs->display)
-        term_printf_async(VNC_ASYNC_EVENT, "VNC: Closing down connection %s\n", vs->display);
 }
 
 int vnc_display_password(DisplayState *ds, const char *password)
 {
-    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
+    VncDisplay *vs = ds ? ds->opaque : vnc_display;
 
     if (vs->password) {
 	qemu_free(vs->password);
@@ -2475,7 +2529,7 @@ int vnc_display_password(DisplayState *ds, const char *password)
 
 int vnc_display_open(DisplayState *ds, const char *display)
 {
-    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
     const char *options;
     int password = 0;
     int reverse = 0;
@@ -2484,6 +2538,8 @@ int vnc_display_open(DisplayState *ds, const char *display)
     int tls = 0, x509 = 0;
 #endif
 
+    if (!vnc_display)
+        return -1;
     vnc_display_close(ds);
     if (strcmp(display, "none") == 0)
 	return 0;
@@ -2587,9 +2643,9 @@ int vnc_display_open(DisplayState *ds, const char *display)
             vs->display = NULL;
             return -1;
         } else {
-            vs->csock = vs->lsock;
+            int csock = vs->lsock;
             vs->lsock = -1;
-            vnc_connect(vs);
+            vnc_connect(vs, csock);
         }
         return 0;
 
@@ -2611,6 +2667,5 @@ int vnc_display_open(DisplayState *ds, const char *display)
             vs->display = dpy;
         }
     }
-
-    return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
+    return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
 }
-- 
1.6.3.rc4.29.g8146