Fix typo
[qemu] / vnc.c
diff --git a/vnc.c b/vnc.c
index 0742387..41defc2 100644 (file)
--- a/vnc.c
+++ b/vnc.c
@@ -28,6 +28,7 @@
 #include "sysemu.h"
 #include "qemu_socket.h"
 #include "qemu-timer.h"
+#include "acl.h"
 
 #define VNC_REFRESH_INTERVAL (1000 / 30)
 
@@ -52,6 +53,7 @@ static char *addr_to_string(const char *format,
     char host[NI_MAXHOST];
     char serv[NI_MAXSERV];
     int err;
+    size_t addrlen;
 
     if ((err = getnameinfo((struct sockaddr *)sa, salen,
                            host, sizeof(host),
@@ -62,8 +64,12 @@ static char *addr_to_string(const char *format,
         return NULL;
     }
 
-    if (asprintf(&addr, format, host, serv) < 0)
-        return NULL;
+    /* Enough for the existing format + the 2 vars we're
+     * subsituting in. */
+    addrlen = strlen(format) + strlen(host) + strlen(serv);
+    addr = qemu_malloc(addrlen + 1);
+    snprintf(addr, addrlen, format, host, serv);
+    addr[addrlen] = '\0';
 
     return addr;
 }
@@ -80,7 +86,6 @@ char *vnc_socket_local_addr(const char *format, int fd) {
     return addr_to_string(format, &sa, salen);
 }
 
-
 char *vnc_socket_remote_addr(const char *format, int fd) {
     struct sockaddr_storage sa;
     socklen_t salen;
@@ -127,10 +132,10 @@ static const char *vnc_auth_name(VncDisplay *vd) {
             return "vencrypt+x509+vnc";
         case VNC_AUTH_VENCRYPT_X509PLAIN:
             return "vencrypt+x509+plain";
-       case VNC_AUTH_VENCRYPT_TLSSASL:
-           return "vencrypt+tls+sasl";
-       case VNC_AUTH_VENCRYPT_X509SASL:
-           return "vencrypt+x509+sasl";
+        case VNC_AUTH_VENCRYPT_TLSSASL:
+            return "vencrypt+tls+sasl";
+        case VNC_AUTH_VENCRYPT_X509SASL:
+            return "vencrypt+x509+sasl";
         default:
             return "vencrypt";
         }
@@ -138,13 +143,11 @@ static const char *vnc_auth_name(VncDisplay *vd) {
         return "vencrypt";
 #endif
     case VNC_AUTH_SASL:
-       return "sasl";
+        return "sasl";
     }
     return "unknown";
 }
 
-#define VNC_SOCKET_FORMAT_PRETTY "local %s:%s"
-
 static void do_info_vnc_client(Monitor *mon, VncState *client)
 {
     char *clientAddr =
@@ -156,6 +159,21 @@ static void do_info_vnc_client(Monitor *mon, VncState *client)
     monitor_printf(mon, "Client:\n");
     monitor_printf(mon, "%s", clientAddr);
     free(clientAddr);
+
+#ifdef CONFIG_VNC_TLS
+    if (client->tls.session &&
+        client->tls.dname)
+        monitor_printf(mon, "  x509 dname: %s\n", client->tls.dname);
+    else
+        monitor_printf(mon, "  x509 dname: none\n");
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (client->sasl.conn &&
+        client->sasl.username)
+        monitor_printf(mon, "    username: %s\n", client->sasl.username);
+    else
+        monitor_printf(mon, "    username: none\n");
+#endif
 }
 
 void do_info_vnc(Monitor *mon)
@@ -244,6 +262,7 @@ static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
 
 static void vnc_update(VncState *vs, int x, int y, int w, int h)
 {
+    struct VncSurface *s = &vs->guest;
     int i;
 
     h += y;
@@ -255,14 +274,14 @@ static void vnc_update(VncState *vs, int x, int y, int w, int h)
     w += (x % 16);
     x -= (x % 16);
 
-    x = MIN(x, vs->serverds.width);
-    y = MIN(y, vs->serverds.height);
-    w = MIN(x + w, vs->serverds.width) - x;
-    h = MIN(h, vs->serverds.height);
+    x = MIN(x, s->ds->width);
+    y = MIN(y, s->ds->height);
+    w = MIN(x + w, s->ds->width) - x;
+    h = MIN(h, s->ds->height);
 
     for (; y < h; y++)
-       for (i = 0; i < w; i += 16)
-           vnc_set_bit(vs->dirty_row[y], (x + i) / 16);
+        for (i = 0; i < w; i += 16)
+            vnc_set_bit(s->dirty[y], (x + i) / 16);
 }
 
 static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
@@ -276,7 +295,7 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
 }
 
 static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
-                                  int32_t encoding)
+                                   int32_t encoding)
 {
     vnc_write_u16(vs, x);
     vnc_write_u16(vs, y);
@@ -289,12 +308,12 @@ static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
 void buffer_reserve(Buffer *buffer, size_t len)
 {
     if ((buffer->capacity - buffer->offset) < len) {
-       buffer->capacity += (len + 1024);
-       buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
-       if (buffer->buffer == NULL) {
-           fprintf(stderr, "vnc: out of memory\n");
-           exit(1);
-       }
+        buffer->capacity += (len + 1024);
+        buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
+        if (buffer->buffer == NULL) {
+            fprintf(stderr, "vnc: out of memory\n");
+            exit(1);
+        }
     }
 }
 
@@ -310,7 +329,7 @@ uint8_t *buffer_end(Buffer *buffer)
 
 void buffer_reset(Buffer *buffer)
 {
-       buffer->offset = 0;
+        buffer->offset = 0;
 }
 
 void buffer_append(Buffer *buffer, const void *data, size_t len)
@@ -322,22 +341,17 @@ void buffer_append(Buffer *buffer, const void *data, size_t len)
 static void vnc_resize(VncState *vs)
 {
     DisplayState *ds = vs->ds;
-
     int size_changed;
 
-    vs->old_data = qemu_realloc(vs->old_data, ds_get_linesize(ds) * ds_get_height(ds));
-
-    if (vs->old_data == NULL) {
-       fprintf(stderr, "vnc: memory allocation failed\n");
-       exit(1);
-    }
-
-    if (ds_get_bytes_per_pixel(ds) != vs->serverds.pf.bytes_per_pixel)
+    /* guest surface */
+    if (!vs->guest.ds)
+        vs->guest.ds = qemu_mallocz(sizeof(*vs->guest.ds));
+    if (ds_get_bytes_per_pixel(ds) != vs->guest.ds->pf.bytes_per_pixel)
         console_color_init(ds);
     vnc_colordepth(vs);
-    size_changed = ds_get_width(ds) != vs->serverds.width ||
-                   ds_get_height(ds) != vs->serverds.height;
-    vs->serverds = *(ds->surface);
+    size_changed = ds_get_width(ds) != vs->guest.ds->width ||
+                   ds_get_height(ds) != vs->guest.ds->height;
+    *(vs->guest.ds) = *(ds->surface);
     if (size_changed) {
         if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
             vnc_write_u8(vs, 0);  /* msg id */
@@ -348,9 +362,17 @@ static void vnc_resize(VncState *vs)
             vnc_flush(vs);
         }
     }
+    memset(vs->guest.dirty, 0xFF, sizeof(vs->guest.dirty));
 
-    memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
-    memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
+    /* server surface */
+    if (!vs->server.ds)
+        vs->server.ds = qemu_mallocz(sizeof(*vs->server.ds));
+    if (vs->server.ds->data)
+        qemu_free(vs->server.ds->data);
+    *(vs->server.ds) = *(ds->surface);
+    vs->server.ds->data = qemu_mallocz(vs->server.ds->linesize *
+                                       vs->server.ds->height);
+    memset(vs->server.dirty, 0xFF, sizeof(vs->guest.dirty));
 }
 
 static void vnc_dpy_resize(DisplayState *ds)
@@ -374,12 +396,12 @@ static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
 {
     uint8_t r, g, b;
 
-    r = ((((v & vs->serverds.pf.rmask) >> vs->serverds.pf.rshift) << vs->clientds.pf.rbits) >>
-        vs->serverds.pf.rbits);
-    g = ((((v & vs->serverds.pf.gmask) >> vs->serverds.pf.gshift) << vs->clientds.pf.gbits) >>
-        vs->serverds.pf.gbits);
-    b = ((((v & vs->serverds.pf.bmask) >> vs->serverds.pf.bshift) << vs->clientds.pf.bbits) >>
-        vs->serverds.pf.bbits);
+    r = ((((v & vs->server.ds->pf.rmask) >> vs->server.ds->pf.rshift) << vs->clientds.pf.rbits) >>
+        vs->server.ds->pf.rbits);
+    g = ((((v & vs->server.ds->pf.gmask) >> vs->server.ds->pf.gshift) << vs->clientds.pf.gbits) >>
+        vs->server.ds->pf.gbits);
+    b = ((((v & vs->server.ds->pf.bmask) >> vs->server.ds->pf.bshift) << vs->clientds.pf.bbits) >>
+        vs->server.ds->pf.bbits);
     v = (r << vs->clientds.pf.rshift) |
         (g << vs->clientds.pf.gshift) |
         (b << vs->clientds.pf.bshift);
@@ -417,7 +439,7 @@ static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
 {
     uint8_t buf[4];
 
-    if (vs->serverds.pf.bytes_per_pixel == 4) {
+    if (vs->server.ds->pf.bytes_per_pixel == 4) {
         uint32_t *pixels = pixels1;
         int n, i;
         n = size >> 2;
@@ -425,7 +447,7 @@ static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
             vnc_convert_pixel(vs, buf, pixels[i]);
             vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
         }
-    } else if (vs->serverds.pf.bytes_per_pixel == 2) {
+    } else if (vs->server.ds->pf.bytes_per_pixel == 2) {
         uint16_t *pixels = pixels1;
         int n, i;
         n = size >> 1;
@@ -433,7 +455,7 @@ static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
             vnc_convert_pixel(vs, buf, pixels[i]);
             vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
         }
-    } else if (vs->serverds.pf.bytes_per_pixel == 1) {
+    } else if (vs->server.ds->pf.bytes_per_pixel == 1) {
         uint8_t *pixels = pixels1;
         int n, i;
         n = size;
@@ -451,10 +473,10 @@ static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h
     int i;
     uint8_t *row;
 
-    row = ds_get_data(vs->ds) + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
+    row = vs->server.ds->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
     for (i = 0; i < h; i++) {
-       vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
-       row += ds_get_linesize(vs->ds);
+        vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
+        row += ds_get_linesize(vs->ds);
     }
 }
 
@@ -500,15 +522,15 @@ static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, i
     int has_fg, has_bg;
     uint8_t *last_fg, *last_bg;
 
-    last_fg = (uint8_t *) qemu_malloc(vs->serverds.pf.bytes_per_pixel);
-    last_bg = (uint8_t *) qemu_malloc(vs->serverds.pf.bytes_per_pixel);
+    last_fg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
+    last_bg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
     has_fg = has_bg = 0;
     for (j = y; j < (y + h); j += 16) {
-       for (i = x; i < (x + w); i += 16) {
+        for (i = x; i < (x + w); i += 16) {
             vs->send_hextile_tile(vs, i, j,
                                   MIN(16, x + w - i), MIN(16, y + h - j),
                                   last_bg, last_fg, &has_bg, &has_fg);
-       }
+        }
     }
     free(last_fg);
     free(last_bg);
@@ -614,22 +636,23 @@ static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int
 static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
 {
     switch(vs->vnc_encoding) {
-       case VNC_ENCODING_ZLIB:
-           send_framebuffer_update_zlib(vs, x, y, w, h);
-           break;
-       case VNC_ENCODING_HEXTILE:
-           vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
-           send_framebuffer_update_hextile(vs, x, y, w, h);
-           break;
-       default:
-           vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
-           send_framebuffer_update_raw(vs, x, y, w, h);
-           break;
+        case VNC_ENCODING_ZLIB:
+            send_framebuffer_update_zlib(vs, x, y, w, h);
+            break;
+        case VNC_ENCODING_HEXTILE:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
+            send_framebuffer_update_hextile(vs, x, y, w, h);
+            break;
+        default:
+            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
+            send_framebuffer_update_raw(vs, x, y, w, h);
+            break;
     }
 }
 
 static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
 {
+    vs->force_update = 1;
     vnc_update_client(vs);
 
     vnc_write_u8(vs, 0);  /* msg id */
@@ -654,16 +677,17 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
     }
 }
 
-static int find_dirty_height(VncState *vs, int y, int last_x, int x)
+static int find_and_clear_dirty_height(struct VncSurface *s,
+                                       int y, int last_x, int x)
 {
     int h;
 
-    for (h = 1; h < (vs->serverds.height - y); h++) {
-       int tmp_x;
-       if (!vnc_get_bit(vs->dirty_row[y + h], last_x))
-           break;
-       for (tmp_x = last_x; tmp_x < x; tmp_x++)
-           vnc_clear_bit(vs->dirty_row[y + h], tmp_x);
+    for (h = 1; h < (s->ds->height - y); h++) {
+        int tmp_x;
+        if (!vnc_get_bit(s->dirty[y + h], last_x))
+            break;
+        for (tmp_x = last_x; tmp_x < x; tmp_x++)
+            vnc_clear_bit(s->dirty[y + h], tmp_x);
     }
 
     return h;
@@ -673,88 +697,102 @@ static void vnc_update_client(void *opaque)
 {
     VncState *vs = opaque;
     if (vs->need_update && vs->csock != -1) {
-       int y;
-       uint8_t *row;
-       char *old_row;
-       uint32_t width_mask[VNC_DIRTY_WORDS];
-       int n_rectangles;
-       int saved_offset;
-       int has_dirty = 0;
+        int y;
+        uint8_t *guest_row;
+        uint8_t *server_row;
+        int cmp_bytes;
+        uint32_t width_mask[VNC_DIRTY_WORDS];
+        int n_rectangles;
+        int saved_offset;
+        int has_dirty = 0;
+
+        if (vs->output.offset && !vs->audio_cap && !vs->force_update) {
+            /* kernel send buffers are full -> drop frames to throttle */
+            qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+            return;
+        }
 
         vga_hw_update();
 
+        /*
+         * Walk through the guest dirty map.
+         * Check and copy modified bits from guest to server surface.
+         * Update server dirty map.
+         */
         vnc_set_bits(width_mask, (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+        cmp_bytes = 16 * ds_get_bytes_per_pixel(vs->ds);
+        guest_row  = vs->guest.ds->data;
+        server_row = vs->server.ds->data;
+        for (y = 0; y < vs->guest.ds->height; y++) {
+            if (vnc_and_bits(vs->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
+                int x;
+                uint8_t *guest_ptr;
+                uint8_t *server_ptr;
+
+                guest_ptr  = guest_row;
+                server_ptr = server_row;
+
+                for (x = 0; x < vs->guest.ds->width;
+                     x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
+                    if (!vnc_get_bit(vs->guest.dirty[y], (x / 16)))
+                        continue;
+                    vnc_clear_bit(vs->guest.dirty[y], (x / 16));
+                    if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
+                        continue;
+                    memcpy(server_ptr, guest_ptr, cmp_bytes);
+                    vnc_set_bit(vs->server.dirty[y], (x / 16));
+                    has_dirty++;
+                }
+            }
+            guest_row  += ds_get_linesize(vs->ds);
+            server_row += ds_get_linesize(vs->ds);
+        }
+
+        if (!has_dirty && !vs->audio_cap && !vs->force_update) {
+            qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+            return;
+        }
 
-       /* Walk through the dirty map and eliminate tiles that
-          really aren't dirty */
-       row = ds_get_data(vs->ds);
-       old_row = vs->old_data;
-
-       for (y = 0; y < ds_get_height(vs->ds); y++) {
-           if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) {
-               int x;
-               uint8_t *ptr;
-               char *old_ptr;
-
-               ptr = row;
-               old_ptr = (char*)old_row;
-
-               for (x = 0; x < ds_get_width(vs->ds); x += 16) {
-                   if (memcmp(old_ptr, ptr, 16 * ds_get_bytes_per_pixel(vs->ds)) == 0) {
-                       vnc_clear_bit(vs->dirty_row[y], (x / 16));
-                   } else {
-                       has_dirty = 1;
-                       memcpy(old_ptr, ptr, 16 * ds_get_bytes_per_pixel(vs->ds));
-                   }
-
-                   ptr += 16 * ds_get_bytes_per_pixel(vs->ds);
-                   old_ptr += 16 * ds_get_bytes_per_pixel(vs->ds);
-               }
-           }
-
-           row += ds_get_linesize(vs->ds);
-           old_row += ds_get_linesize(vs->ds);
-       }
-
-       if (!has_dirty && !vs->audio_cap) {
-           qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
-           return;
-       }
-
-       /* Count rectangles */
-       n_rectangles = 0;
-       vnc_write_u8(vs, 0);  /* msg id */
-       vnc_write_u8(vs, 0);
-       saved_offset = vs->output.offset;
-       vnc_write_u16(vs, 0);
-
-       for (y = 0; y < vs->serverds.height; y++) {
-           int x;
-           int last_x = -1;
-           for (x = 0; x < vs->serverds.width / 16; x++) {
-               if (vnc_get_bit(vs->dirty_row[y], x)) {
-                   if (last_x == -1) {
-                       last_x = x;
-                   }
-                   vnc_clear_bit(vs->dirty_row[y], x);
-               } else {
-                   if (last_x != -1) {
-                       int h = find_dirty_height(vs, y, last_x, x);
-                       send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
-                       n_rectangles++;
-                   }
-                   last_x = -1;
-               }
-           }
-           if (last_x != -1) {
-               int h = find_dirty_height(vs, y, last_x, x);
-               send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
-               n_rectangles++;
-           }
-       }
-       vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
-       vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
-       vnc_flush(vs);
+        /*
+         * Send screen updates to the vnc client using the server
+         * surface and server dirty map.  guest surface updates
+         * happening in parallel don't disturb us, the next pass will
+         * send them to the client.
+         */
+        n_rectangles = 0;
+        vnc_write_u8(vs, 0);  /* msg id */
+        vnc_write_u8(vs, 0);
+        saved_offset = vs->output.offset;
+        vnc_write_u16(vs, 0);
+
+        for (y = 0; y < vs->server.ds->height; y++) {
+            int x;
+            int last_x = -1;
+            for (x = 0; x < vs->server.ds->width / 16; x++) {
+                if (vnc_get_bit(vs->server.dirty[y], x)) {
+                    if (last_x == -1) {
+                        last_x = x;
+                    }
+                    vnc_clear_bit(vs->server.dirty[y], x);
+                } else {
+                    if (last_x != -1) {
+                        int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
+                        send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
+                        n_rectangles++;
+                    }
+                    last_x = -1;
+                }
+            }
+            if (last_x != -1) {
+                int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
+                send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
+                n_rectangles++;
+            }
+        }
+        vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+        vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
+        vnc_flush(vs);
+        vs->force_update = 0;
 
     }
 
@@ -816,7 +854,7 @@ static void audio_add(VncState *vs)
     ops.destroy = audio_capture_destroy;
     ops.capture = audio_capture;
 
-    vs->audio_cap = AUD_add_capture(NULL, &vs->as, &ops, vs);
+    vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
     if (!vs->audio_cap) {
         monitor_printf(mon, "Failed to add audio capture\n");
     }
@@ -847,15 +885,15 @@ 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);
+        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);
         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
-       vnc_tls_client_cleanup(vs);
+        vnc_tls_client_cleanup(vs);
 #endif /* CONFIG_VNC_TLS */
 #ifdef CONFIG_VNC_SASL
         vnc_sasl_client_cleanup(vs);
@@ -876,10 +914,12 @@ int vnc_client_io_error(VncState *vs, int ret, int last_errno)
         if (!vs->vd->clients)
             dcl->idle = 1;
 
-        qemu_free(vs->old_data);
+        qemu_free(vs->server.ds->data);
+        qemu_free(vs->server.ds);
+        qemu_free(vs->guest.ds);
         qemu_free(vs);
-  
-       return 0;
+
+        return 0;
     }
     return ret;
 }
@@ -911,18 +951,18 @@ long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
     long ret;
 #ifdef CONFIG_VNC_TLS
     if (vs->tls.session) {
-       ret = gnutls_write(vs->tls.session, data, datalen);
-       if (ret < 0) {
-           if (ret == GNUTLS_E_AGAIN)
-               errno = EAGAIN;
-           else
-               errno = EIO;
-           ret = -1;
-       }
+        ret = gnutls_write(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
     } else
 #endif /* CONFIG_VNC_TLS */
-       ret = send(vs->csock, data, datalen, 0);
-    VNC_DEBUG("Wrote wire %p %d -> %ld\n", data, datalen, ret);
+        ret = send(vs->csock, data, datalen, 0);
+    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
     return vnc_client_io_error(vs, ret, socket_error());
 }
 
@@ -942,7 +982,7 @@ static long vnc_client_write_plain(VncState *vs)
     long ret;
 
 #ifdef CONFIG_VNC_SASL
-    VNC_DEBUG("Write Plain: Pending output %p size %d offset %d. Wait SSF %d\n",
+    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
               vs->output.buffer, vs->output.capacity, vs->output.offset,
               vs->sasl.waitWriteSSF);
 
@@ -962,7 +1002,7 @@ static long vnc_client_write_plain(VncState *vs)
     vs->output.offset -= ret;
 
     if (vs->output.offset == 0) {
-       qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
     }
 
     return ret;
@@ -1016,18 +1056,18 @@ long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
     long ret;
 #ifdef CONFIG_VNC_TLS
     if (vs->tls.session) {
-       ret = gnutls_read(vs->tls.session, data, datalen);
-       if (ret < 0) {
-           if (ret == GNUTLS_E_AGAIN)
-               errno = EAGAIN;
-           else
-               errno = EIO;
-           ret = -1;
-       }
+        ret = gnutls_read(vs->tls.session, data, datalen);
+        if (ret < 0) {
+            if (ret == GNUTLS_E_AGAIN)
+                errno = EAGAIN;
+            else
+                errno = EIO;
+            ret = -1;
+        }
     } else
 #endif /* CONFIG_VNC_TLS */
-       ret = recv(vs->csock, data, datalen, 0);
-    VNC_DEBUG("Read wire %p %d -> %ld\n", data, datalen, ret);
+        ret = recv(vs->csock, data, datalen, 0);
+    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
     return vnc_client_io_error(vs, ret, socket_error());
 }
 
@@ -1043,7 +1083,7 @@ long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
 static long vnc_client_read_plain(VncState *vs)
 {
     int ret;
-    VNC_DEBUG("Read plain %p size %d offset %d\n",
+    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
               vs->input.buffer, vs->input.capacity, vs->input.offset);
     buffer_reserve(&vs->input, 4096);
     ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
@@ -1071,22 +1111,22 @@ void vnc_client_read(void *opaque)
 #endif /* CONFIG_VNC_SASL */
         ret = vnc_client_read_plain(vs);
     if (!ret)
-       return;
+        return;
 
     while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
-       size_t len = vs->read_handler_expect;
-       int ret;
-
-       ret = vs->read_handler(vs, vs->input.buffer, len);
-       if (vs->csock == -1)
-           return;
-
-       if (!ret) {
-           memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
-           vs->input.offset -= len;
-       } else {
-           vs->read_handler_expect = ret;
-       }
+        size_t len = vs->read_handler_expect;
+        int ret;
+
+        ret = vs->read_handler(vs, vs->input.buffer, len);
+        if (vs->csock == -1)
+            return;
+
+        if (!ret) {
+            memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
+            vs->input.offset -= len;
+        } else {
+            vs->read_handler_expect = ret;
+        }
     }
 }
 
@@ -1095,7 +1135,7 @@ void vnc_write(VncState *vs, const void *data, size_t len)
     buffer_reserve(&vs->output, len);
 
     if (buffer_empty(&vs->output)) {
-       qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
     }
 
     buffer_append(&vs->output, data, len);
@@ -1136,7 +1176,7 @@ void vnc_write_u8(VncState *vs, uint8_t value)
 void vnc_flush(VncState *vs)
 {
     if (vs->output.offset)
-       vnc_client_write(vs);
+        vnc_client_write(vs);
 }
 
 uint8_t read_u8(uint8_t *data, size_t offset)
@@ -1152,13 +1192,13 @@ uint16_t read_u16(uint8_t *data, size_t offset)
 int32_t read_s32(uint8_t *data, size_t offset)
 {
     return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
-                    (data[offset + 2] << 8) | data[offset + 3]);
+                     (data[offset + 2] << 8) | data[offset + 3]);
 }
 
 uint32_t read_u32(uint8_t *data, size_t offset)
 {
     return ((data[offset] << 24) | (data[offset + 1] << 16) |
-           (data[offset + 2] << 8) | data[offset + 3]);
+            (data[offset + 2] << 8) | data[offset + 3]);
 }
 
 static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
@@ -1168,13 +1208,13 @@ static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
 static void check_pointer_type_change(VncState *vs, int absolute)
 {
     if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
-       vnc_write_u8(vs, 0);
-       vnc_write_u8(vs, 0);
-       vnc_write_u16(vs, 1);
-       vnc_framebuffer_update(vs, absolute, 0,
-                              ds_get_width(vs->ds), ds_get_height(vs->ds),
+        vnc_write_u8(vs, 0);
+        vnc_write_u8(vs, 0);
+        vnc_write_u16(vs, 1);
+        vnc_framebuffer_update(vs, absolute, 0,
+                               ds_get_width(vs->ds), ds_get_height(vs->ds),
                                VNC_ENCODING_POINTER_TYPE_CHANGE);
-       vnc_flush(vs);
+        vnc_flush(vs);
     }
     vs->absolute = absolute;
 }
@@ -1185,32 +1225,32 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
     int dz = 0;
 
     if (button_mask & 0x01)
-       buttons |= MOUSE_EVENT_LBUTTON;
+        buttons |= MOUSE_EVENT_LBUTTON;
     if (button_mask & 0x02)
-       buttons |= MOUSE_EVENT_MBUTTON;
+        buttons |= MOUSE_EVENT_MBUTTON;
     if (button_mask & 0x04)
-       buttons |= MOUSE_EVENT_RBUTTON;
+        buttons |= MOUSE_EVENT_RBUTTON;
     if (button_mask & 0x08)
-       dz = -1;
+        dz = -1;
     if (button_mask & 0x10)
-       dz = 1;
+        dz = 1;
 
     if (vs->absolute) {
-       kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
-                       y * 0x7FFF / (ds_get_height(vs->ds) - 1),
-                       dz, buttons);
+        kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
+                        y * 0x7FFF / (ds_get_height(vs->ds) - 1),
+                        dz, buttons);
     } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
-       x -= 0x7FFF;
-       y -= 0x7FFF;
+        x -= 0x7FFF;
+        y -= 0x7FFF;
 
-       kbd_mouse_event(x, y, dz, buttons);
+        kbd_mouse_event(x, y, dz, buttons);
     } else {
-       if (vs->last_x != -1)
-           kbd_mouse_event(x - vs->last_x,
-                           y - vs->last_y,
-                           dz, buttons);
-       vs->last_x = x;
-       vs->last_y = y;
+        if (vs->last_x != -1)
+            kbd_mouse_event(x - vs->last_x,
+                            y - vs->last_y,
+                            dz, buttons);
+        vs->last_x = x;
+        vs->last_y = y;
     }
 
     check_pointer_type_change(vs, kbd_mouse_is_absolute());
@@ -1258,8 +1298,8 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
             return;
         }
         break;
-    case 0x3a:                 /* CapsLock */
-    case 0x45:                 /* NumLock */
+    case 0x3a:                        /* CapsLock */
+    case 0x45:                        /* NumLock */
         if (!down)
             vs->modifiers_state[keycode] ^= 1;
         break;
@@ -1302,30 +1342,39 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
             case 0xb8:                          /* Right ALT */
                 break;
             case 0xc8:
+            case 0x48:
                 kbd_put_keysym(QEMU_KEY_UP);
                 break;
             case 0xd0:
+            case 0x50:
                 kbd_put_keysym(QEMU_KEY_DOWN);
                 break;
             case 0xcb:
+            case 0x4b:
                 kbd_put_keysym(QEMU_KEY_LEFT);
                 break;
             case 0xcd:
+            case 0x4d:
                 kbd_put_keysym(QEMU_KEY_RIGHT);
                 break;
             case 0xd3:
+            case 0x53:
                 kbd_put_keysym(QEMU_KEY_DELETE);
                 break;
             case 0xc7:
+            case 0x47:
                 kbd_put_keysym(QEMU_KEY_HOME);
                 break;
             case 0xcf:
+            case 0x4f:
                 kbd_put_keysym(QEMU_KEY_END);
                 break;
             case 0xc9:
+            case 0x49:
                 kbd_put_keysym(QEMU_KEY_PAGEUP);
                 break;
             case 0xd1:
+            case 0x51:
                 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
                 break;
             default:
@@ -1341,7 +1390,7 @@ static void key_event(VncState *vs, int down, uint32_t sym)
     int keycode;
 
     if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
-       sym = sym - 'A' + 'a';
+        sym = sym - 'A' + 'a';
 
     keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF);
     do_key_event(vs, down, keycode, sym);
@@ -1358,8 +1407,8 @@ static void ext_key_event(VncState *vs, int down,
 }
 
 static void framebuffer_update_request(VncState *vs, int incremental,
-                                      int x_position, int y_position,
-                                      int w, int h)
+                                       int x_position, int y_position,
+                                       int w, int h)
 {
     if (x_position > ds_get_width(vs->ds))
         x_position = ds_get_width(vs->ds);
@@ -1373,14 +1422,13 @@ static void framebuffer_update_request(VncState *vs, int incremental,
     int i;
     vs->need_update = 1;
     if (!incremental) {
-       char *old_row = vs->old_data + y_position * ds_get_linesize(vs->ds);
-
-       for (i = 0; i < h; i++) {
-            vnc_set_bits(vs->dirty_row[y_position + i],
+        vs->force_update = 1;
+        for (i = 0; i < h; i++) {
+            vnc_set_bits(vs->guest.dirty[y_position + i],
                          (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
-           memset(old_row, 42, ds_get_width(vs->ds) * ds_get_bytes_per_pixel(vs->ds));
-           old_row += ds_get_linesize(vs->ds);
-       }
+            vnc_set_bits(vs->server.dirty[y_position + i],
+                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
+        }
     }
 }
 
@@ -1497,17 +1545,17 @@ static void set_pixel_conversion(VncState *vs)
 }
 
 static void set_pixel_format(VncState *vs,
-                            int bits_per_pixel, int depth,
-                            int big_endian_flag, int true_color_flag,
-                            int red_max, int green_max, int blue_max,
-                            int red_shift, int green_shift, int blue_shift)
+                             int bits_per_pixel, int depth,
+                             int big_endian_flag, int true_color_flag,
+                             int red_max, int green_max, int blue_max,
+                             int red_shift, int green_shift, int blue_shift)
 {
     if (!true_color_flag) {
-       vnc_client_error(vs);
+        vnc_client_error(vs);
         return;
     }
 
-    vs->clientds = vs->serverds;
+    vs->clientds = *(vs->guest.ds);
     vs->clientds.pf.rmax = red_max;
     count_bits(vs->clientds.pf.rbits, red_max);
     vs->clientds.pf.rshift = red_shift;
@@ -1556,7 +1604,7 @@ static void pixel_format_message (VncState *vs) {
     else if (vs->ds->surface->pf.bits_per_pixel == 8)
         vs->send_hextile_tile = send_hextile_tile_8;
     vs->clientds = *(vs->ds->surface);
-    vs->clientds.flags |= ~QEMU_ALLOCATED_FLAG;
+    vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
     vs->write_pixels = vnc_write_pixels_copy;
 
     vnc_write(vs, pad, 3);           /* padding */
@@ -1590,65 +1638,65 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
 
     switch (data[0]) {
     case 0:
-       if (len == 1)
-           return 20;
-
-       set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
-                        read_u8(data, 6), read_u8(data, 7),
-                        read_u16(data, 8), read_u16(data, 10),
-                        read_u16(data, 12), read_u8(data, 14),
-                        read_u8(data, 15), read_u8(data, 16));
-       break;
+        if (len == 1)
+            return 20;
+
+        set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
+                         read_u8(data, 6), read_u8(data, 7),
+                         read_u16(data, 8), read_u16(data, 10),
+                         read_u16(data, 12), read_u8(data, 14),
+                         read_u8(data, 15), read_u8(data, 16));
+        break;
     case 2:
-       if (len == 1)
-           return 4;
+        if (len == 1)
+            return 4;
 
-       if (len == 4) {
+        if (len == 4) {
             limit = read_u16(data, 2);
             if (limit > 0)
                 return 4 + (limit * 4);
         } else
             limit = read_u16(data, 2);
 
-       for (i = 0; i < limit; i++) {
-           int32_t val = read_s32(data, 4 + (i * 4));
-           memcpy(data + 4 + (i * 4), &val, sizeof(val));
-       }
+        for (i = 0; i < limit; i++) {
+            int32_t val = read_s32(data, 4 + (i * 4));
+            memcpy(data + 4 + (i * 4), &val, sizeof(val));
+        }
 
-       set_encodings(vs, (int32_t *)(data + 4), limit);
-       break;
+        set_encodings(vs, (int32_t *)(data + 4), limit);
+        break;
     case 3:
-       if (len == 1)
-           return 10;
+        if (len == 1)
+            return 10;
 
-       framebuffer_update_request(vs,
-                                  read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
-                                  read_u16(data, 6), read_u16(data, 8));
-       break;
+        framebuffer_update_request(vs,
+                                   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
+                                   read_u16(data, 6), read_u16(data, 8));
+        break;
     case 4:
-       if (len == 1)
-           return 8;
+        if (len == 1)
+            return 8;
 
-       key_event(vs, read_u8(data, 1), read_u32(data, 4));
-       break;
+        key_event(vs, read_u8(data, 1), read_u32(data, 4));
+        break;
     case 5:
-       if (len == 1)
-           return 6;
+        if (len == 1)
+            return 6;
 
-       pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
-       break;
+        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
+        break;
     case 6:
-       if (len == 1)
-           return 8;
+        if (len == 1)
+            return 8;
 
-       if (len == 8) {
+        if (len == 8) {
             uint32_t dlen = read_u32(data, 4);
             if (dlen > 0)
                 return 8 + dlen;
         }
 
-       client_cut_text(vs, read_u32(data, 4), data + 8);
-       break;
+        client_cut_text(vs, read_u32(data, 4), data + 8);
+        break;
     case 255:
         if (len == 1)
             return 2;
@@ -1710,9 +1758,9 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
         }
         break;
     default:
-       printf("Msg: %d\n", data[0]);
-       vnc_client_error(vs);
-       break;
+        printf("Msg: %d\n", data[0]);
+        vnc_client_error(vs);
+        break;
     }
 
     vnc_read_when(vs, protocol_client_msg, 1);
@@ -1765,16 +1813,16 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
     unsigned char key[8];
 
     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) {
-           static const char err[] = "Authentication failed";
-           vnc_write_u32(vs, sizeof(err));
-           vnc_write(vs, err, sizeof(err));
-       }
-       vnc_flush(vs);
-       vnc_client_error(vs);
-       return 0;
+        VNC_DEBUG("No password configured on server");
+        vnc_write_u32(vs, 1); /* Reject auth */
+        if (vs->minor >= 8) {
+            static const char err[] = "Authentication failed";
+            vnc_write_u32(vs, sizeof(err));
+            vnc_write(vs, err, sizeof(err));
+        }
+        vnc_flush(vs);
+        vnc_client_error(vs);
+        return 0;
     }
 
     memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
@@ -1789,19 +1837,19 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
 
     /* Compare expected vs actual challenge response */
     if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
-       VNC_DEBUG("Client challenge reponse did not match\n");
-       vnc_write_u32(vs, 1); /* Reject auth */
-       if (vs->minor >= 8) {
-           static const char err[] = "Authentication failed";
-           vnc_write_u32(vs, sizeof(err));
-           vnc_write(vs, err, sizeof(err));
-       }
-       vnc_flush(vs);
-       vnc_client_error(vs);
+        VNC_DEBUG("Client challenge reponse did not match\n");
+        vnc_write_u32(vs, 1); /* Reject auth */
+        if (vs->minor >= 8) {
+            static const char err[] = "Authentication failed";
+            vnc_write_u32(vs, sizeof(err));
+            vnc_write(vs, err, sizeof(err));
+        }
+        vnc_flush(vs);
+        vnc_client_error(vs);
     } else {
-       VNC_DEBUG("Accepting VNC challenge response\n");
-       vnc_write_u32(vs, 0); /* Accept auth */
-       vnc_flush(vs);
+        VNC_DEBUG("Accepting VNC challenge response\n");
+        vnc_write_u32(vs, 0); /* Accept auth */
+        vnc_flush(vs);
 
         start_client_init(vs);
     }
@@ -1824,7 +1872,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->vd->auth) { /* Reject auth */
-       VNC_DEBUG("Reject auth %d\n", (int)data[0]);
+       VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
        vnc_write_u32(vs, 1);
        if (vs->minor >= 8) {
            static const char err[] = "Authentication failed";
@@ -1864,7 +1912,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
 #endif /* CONFIG_VNC_SASL */
 
        default: /* Should not be possible, but just in case */
-           VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
+           VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
            vnc_write_u8(vs, 1);
            if (vs->minor >= 8) {
                static const char err[] = "Authentication failed";
@@ -1885,35 +1933,35 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
     local[12] = 0;
 
     if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
-       VNC_DEBUG("Malformed protocol version %s\n", local);
-       vnc_client_error(vs);
-       return 0;
+        VNC_DEBUG("Malformed protocol version %s\n", local);
+        vnc_client_error(vs);
+        return 0;
     }
     VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
     if (vs->major != 3 ||
-       (vs->minor != 3 &&
-        vs->minor != 4 &&
-        vs->minor != 5 &&
-        vs->minor != 7 &&
-        vs->minor != 8)) {
-       VNC_DEBUG("Unsupported client version\n");
-       vnc_write_u32(vs, VNC_AUTH_INVALID);
-       vnc_flush(vs);
-       vnc_client_error(vs);
-       return 0;
+        (vs->minor != 3 &&
+         vs->minor != 4 &&
+         vs->minor != 5 &&
+         vs->minor != 7 &&
+         vs->minor != 8)) {
+        VNC_DEBUG("Unsupported client version\n");
+        vnc_write_u32(vs, VNC_AUTH_INVALID);
+        vnc_flush(vs);
+        vnc_client_error(vs);
+        return 0;
     }
     /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
      * as equivalent to v3.3 by servers
      */
     if (vs->minor == 4 || vs->minor == 5)
-       vs->minor = 3;
+        vs->minor = 3;
 
     if (vs->minor == 3) {
-       if (vs->vd->auth == VNC_AUTH_NONE) {
+        if (vs->vd->auth == VNC_AUTH_NONE) {
             VNC_DEBUG("Tell client auth none\n");
             vnc_write_u32(vs, vs->vd->auth);
             vnc_flush(vs);
-           start_client_init(vs);
+            start_client_init(vs);
        } else if (vs->vd->auth == VNC_AUTH_VNC) {
             VNC_DEBUG("Tell client VNC auth\n");
             vnc_write_u32(vs, vs->vd->auth);
@@ -1926,11 +1974,11 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
             vnc_client_error(vs);
        }
     } else {
-       VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
-       vnc_write_u8(vs, 1); /* num auth */
-       vnc_write_u8(vs, vs->vd->auth);
-       vnc_read_when(vs, protocol_client_auth, 1);
-       vnc_flush(vs);
+        VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
+        vnc_write_u8(vs, 1); /* num auth */
+        vnc_write_u8(vs, vs->vd->auth);
+        vnc_read_when(vs, protocol_client_auth, 1);
+        vnc_flush(vs);
     }
 
     return 0;
@@ -1961,8 +2009,6 @@ static void vnc_connect(VncDisplay *vd, int csock)
     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->dirty_row, 0xFF, sizeof(vs->dirty_row));
     vnc_update_client(vs);
     reset_keys(vs);
 
@@ -1987,9 +2033,8 @@ static void vnc_listen_read(void *opaque)
 
 void vnc_display_init(DisplayState *ds)
 {
-    VncDisplay *vs;
+    VncDisplay *vs = qemu_mallocz(sizeof(*vs));
 
-    vs = qemu_mallocz(sizeof(VncState));
     dcl = qemu_mallocz(sizeof(DisplayChangeListener));
 
     ds->opaque = vs;
@@ -2006,7 +2051,7 @@ void vnc_display_init(DisplayState *ds)
         vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
 
     if (!vs->kbd_layout)
-       exit(1);
+        exit(1);
 
     dcl->dpy_copy = vnc_dpy_copy;
     dcl->dpy_update = vnc_dpy_update;
@@ -2023,13 +2068,13 @@ void vnc_display_close(DisplayState *ds)
     if (!vs)
         return;
     if (vs->display) {
-       qemu_free(vs->display);
-       vs->display = NULL;
+        qemu_free(vs->display);
+        vs->display = NULL;
     }
     if (vs->lsock != -1) {
-       qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
-       close(vs->lsock);
-       vs->lsock = -1;
+        qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
+        close(vs->lsock);
+        vs->lsock = -1;
     }
     vs->auth = VNC_AUTH_INVALID;
 #ifdef CONFIG_VNC_TLS
@@ -2043,17 +2088,24 @@ int vnc_display_password(DisplayState *ds, const char *password)
     VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
 
     if (vs->password) {
-       qemu_free(vs->password);
-       vs->password = NULL;
+        qemu_free(vs->password);
+        vs->password = NULL;
     }
     if (password && password[0]) {
-       if (!(vs->password = qemu_strdup(password)))
-           return -1;
+        if (!(vs->password = qemu_strdup(password)))
+            return -1;
     }
 
     return 0;
 }
 
+char *vnc_display_local_addr(DisplayState *ds)
+{
+    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
+    
+    return vnc_socket_local_addr("%s:%s", vs->lsock);
+}
+
 int vnc_display_open(DisplayState *ds, const char *display)
 {
     VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
@@ -2068,65 +2120,85 @@ int vnc_display_open(DisplayState *ds, const char *display)
     int sasl = 0;
     int saslErr;
 #endif
+    int acl = 0;
 
     if (!vnc_display)
         return -1;
     vnc_display_close(ds);
     if (strcmp(display, "none") == 0)
-       return 0;
+        return 0;
 
     if (!(vs->display = strdup(display)))
-       return -1;
+        return -1;
 
     options = display;
     while ((options = strchr(options, ','))) {
-       options++;
-       if (strncmp(options, "password", 8) == 0) {
-           password = 1; /* Require password auth */
-       } else if (strncmp(options, "reverse", 7) == 0) {
-           reverse = 1;
-       } else if (strncmp(options, "to=", 3) == 0) {
+        options++;
+        if (strncmp(options, "password", 8) == 0) {
+            password = 1; /* Require password auth */
+        } else if (strncmp(options, "reverse", 7) == 0) {
+            reverse = 1;
+        } else if (strncmp(options, "to=", 3) == 0) {
             to_port = atoi(options+3) + 5900;
 #ifdef CONFIG_VNC_SASL
-       } else if (strncmp(options, "sasl", 4) == 0) {
-           sasl = 1; /* Require SASL auth */
+        } else if (strncmp(options, "sasl", 4) == 0) {
+            sasl = 1; /* Require SASL auth */
 #endif
 #ifdef CONFIG_VNC_TLS
-       } else if (strncmp(options, "tls", 3) == 0) {
-           tls = 1; /* Require TLS */
-       } else if (strncmp(options, "x509", 4) == 0) {
-           char *start, *end;
-           x509 = 1; /* Require x509 certificates */
-           if (strncmp(options, "x509verify", 10) == 0)
-               vs->tls.x509verify = 1; /* ...and verify client certs */
-
-           /* Now check for 'x509=/some/path' postfix
-            * and use that to setup x509 certificate/key paths */
-           start = strchr(options, '=');
-           end = strchr(options, ',');
-           if (start && (!end || (start < end))) {
-               int len = end ? end-(start+1) : strlen(start+1);
-               char *path = qemu_strndup(start + 1, len);
-
-               VNC_DEBUG("Trying certificate path '%s'\n", path);
-               if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
-                   fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
-                   qemu_free(path);
-                   qemu_free(vs->display);
-                   vs->display = NULL;
-                   return -1;
-               }
-               qemu_free(path);
-           } else {
-               fprintf(stderr, "No certificate path provided\n");
-               qemu_free(vs->display);
-               vs->display = NULL;
-               return -1;
-           }
+        } else if (strncmp(options, "tls", 3) == 0) {
+            tls = 1; /* Require TLS */
+        } else if (strncmp(options, "x509", 4) == 0) {
+            char *start, *end;
+            x509 = 1; /* Require x509 certificates */
+            if (strncmp(options, "x509verify", 10) == 0)
+                vs->tls.x509verify = 1; /* ...and verify client certs */
+
+            /* Now check for 'x509=/some/path' postfix
+             * and use that to setup x509 certificate/key paths */
+            start = strchr(options, '=');
+            end = strchr(options, ',');
+            if (start && (!end || (start < end))) {
+                int len = end ? end-(start+1) : strlen(start+1);
+                char *path = qemu_strndup(start + 1, len);
+
+                VNC_DEBUG("Trying certificate path '%s'\n", path);
+                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
+                    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
+                    qemu_free(path);
+                    qemu_free(vs->display);
+                    vs->display = NULL;
+                    return -1;
+                }
+                qemu_free(path);
+            } else {
+                fprintf(stderr, "No certificate path provided\n");
+                qemu_free(vs->display);
+                vs->display = NULL;
+                return -1;
+            }
 #endif
-       }
+        } else if (strncmp(options, "acl", 3) == 0) {
+            acl = 1;
+        }
     }
 
+#ifdef CONFIG_VNC_TLS
+    if (acl && x509 && vs->tls.x509verify) {
+        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
+            fprintf(stderr, "Failed to create x509 dname ACL\n");
+            exit(1);
+        }
+    }
+#endif
+#ifdef CONFIG_VNC_SASL
+    if (acl && sasl) {
+        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
+            fprintf(stderr, "Failed to create username ACL\n");
+            exit(1);
+        }
+    }
+#endif
+
     /*
      * Combinations we support here:
      *
@@ -2145,22 +2217,22 @@ int vnc_display_open(DisplayState *ds, const char *display)
      */
     if (password) {
 #ifdef CONFIG_VNC_TLS
-       if (tls) {
-           vs->auth = VNC_AUTH_VENCRYPT;
-           if (x509) {
-               VNC_DEBUG("Initializing VNC server with x509 password auth\n");
-               vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
-           } else {
-               VNC_DEBUG("Initializing VNC server with TLS password auth\n");
-               vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
-           }
-       } else {
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+            }
+        } else {
 #endif /* CONFIG_VNC_TLS */
-           VNC_DEBUG("Initializing VNC server with password auth\n");
-           vs->auth = VNC_AUTH_VNC;
+            VNC_DEBUG("Initializing VNC server with password auth\n");
+            vs->auth = VNC_AUTH_VNC;
 #ifdef CONFIG_VNC_TLS
-           vs->subauth = VNC_AUTH_INVALID;
-       }
+            vs->subauth = VNC_AUTH_INVALID;
+        }
 #endif /* CONFIG_VNC_TLS */
 #ifdef CONFIG_VNC_SASL
     } else if (sasl) {
@@ -2168,15 +2240,15 @@ int vnc_display_open(DisplayState *ds, const char *display)
         if (tls) {
             vs->auth = VNC_AUTH_VENCRYPT;
             if (x509) {
-               VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
+                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
                 vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
             } else {
-               VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
+                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
                 vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
             }
         } else {
 #endif /* CONFIG_VNC_TLS */
-           VNC_DEBUG("Initializing VNC server with SASL auth\n");
+            VNC_DEBUG("Initializing VNC server with SASL auth\n");
             vs->auth = VNC_AUTH_SASL;
 #ifdef CONFIG_VNC_TLS
             vs->subauth = VNC_AUTH_INVALID;
@@ -2185,22 +2257,22 @@ int vnc_display_open(DisplayState *ds, const char *display)
 #endif /* CONFIG_VNC_SASL */
     } else {
 #ifdef CONFIG_VNC_TLS
-       if (tls) {
-           vs->auth = VNC_AUTH_VENCRYPT;
-           if (x509) {
-               VNC_DEBUG("Initializing VNC server with x509 no auth\n");
-               vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
-           } else {
-               VNC_DEBUG("Initializing VNC server with TLS no auth\n");
-               vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
-           }
-       } else {
+        if (tls) {
+            vs->auth = VNC_AUTH_VENCRYPT;
+            if (x509) {
+                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
+            } else {
+                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
+                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+            }
+        } else {
 #endif
-           VNC_DEBUG("Initializing VNC server with no auth\n");
-           vs->auth = VNC_AUTH_NONE;
+            VNC_DEBUG("Initializing VNC server with no auth\n");
+            vs->auth = VNC_AUTH_NONE;
 #ifdef CONFIG_VNC_TLS
-           vs->subauth = VNC_AUTH_INVALID;
-       }
+            vs->subauth = VNC_AUTH_INVALID;
+        }
 #endif
     }