]> git.proxmox.com Git - qemu.git/blobdiff - vnc.c
Add machine type aliases
[qemu.git] / vnc.c
diff --git a/vnc.c b/vnc.c
index 7b1c227cef93d8be2afc13f54c73d2640e3b1675..de0ff872d42baf135be06cdc601e700c1b2b94b4 100644 (file)
--- a/vnc.c
+++ b/vnc.c
@@ -65,7 +65,7 @@ static char *addr_to_string(const char *format,
     }
 
     /* Enough for the existing format + the 2 vars we're
-     * subsituting in. */
+     * substituting in. */
     addrlen = strlen(format) + strlen(host) + strlen(serv);
     addr = qemu_malloc(addrlen + 1);
     snprintf(addr, addrlen, format, host, serv);
@@ -86,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;
@@ -217,6 +216,8 @@ static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
 */
 
 static void vnc_update_client(void *opaque);
+static void vnc_disconnect_start(VncState *vs);
+static void vnc_disconnect_finish(VncState *vs);
 
 static void vnc_colordepth(VncState *vs);
 
@@ -366,17 +367,13 @@ static void vnc_resize(VncState *vs)
     memset(vs->guest.dirty, 0xFF, sizeof(vs->guest.dirty));
 
     /* server surface */
-    if (!vs->server.ds) {
-        vs->server.ds = default_allocator.create_displaysurface(ds_get_width(ds),
-                                                                ds_get_height(ds));
-    } else {
-        default_allocator.resize_displaysurface(vs->server.ds,
-                                                ds_get_width(ds), ds_get_height(ds));
-    }
-    if (vs->server.ds->data == NULL) {
-        fprintf(stderr, "vnc: memory allocation failed\n");
-        exit(1);
-    }
+    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));
 }
 
@@ -657,9 +654,6 @@ static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
 
 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 */
     vnc_write_u8(vs, 0);
     vnc_write_u16(vs, 1); /* number of rects */
@@ -672,13 +666,22 @@ static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, i
 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 = vd->clients;
-    while (vs != NULL) {
+    VncState *vs, *vn;
+
+    for (vs = vd->clients; vs != NULL; vs = vn) {
+        vn = vs->next;
+        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
+            vs->force_update = 1;
+            vnc_update_client(vs);
+            /* vs might be free()ed here */
+        }
+    }
+
+    for (vs = vd->clients; vs != NULL; vs = vs->next) {
         if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
             vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
         else /* TODO */
             vnc_update(vs, dst_x, dst_y, w, h);
-        vs = vs->next;
     }
 }
 
@@ -687,7 +690,7 @@ static int find_and_clear_dirty_height(struct VncSurface *s,
 {
     int h;
 
-    for (h = 1; h < (s->ds->height - y) && h < 1; h++) {
+    for (h = 1; h < (s->ds->height - y); h++) {
         int tmp_x;
         if (!vnc_get_bit(s->dirty[y + h], last_x))
             break;
@@ -803,6 +806,8 @@ static void vnc_update_client(void *opaque)
 
     if (vs->csock != -1) {
         qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
+    } else {
+        vnc_disconnect_finish(vs);
     }
 
 }
@@ -859,7 +864,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");
     }
@@ -873,6 +878,48 @@ static void audio_del(VncState *vs)
     }
 }
 
+static void vnc_disconnect_start(VncState *vs)
+{
+    if (vs->csock == -1)
+        return;
+    qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
+    closesocket(vs->csock);
+    vs->csock = -1;
+}
+
+static void vnc_disconnect_finish(VncState *vs)
+{
+    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);
+#endif /* CONFIG_VNC_TLS */
+#ifdef CONFIG_VNC_SASL
+    vnc_sasl_client_cleanup(vs);
+#endif /* CONFIG_VNC_SASL */
+    audio_del(vs);
+
+    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)
+        dcl->idle = 1;
+
+    qemu_free(vs->server.ds->data);
+    qemu_free(vs->server.ds);
+    qemu_free(vs->guest.ds);
+    qemu_free(vs);
+}
 
 int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 {
@@ -890,38 +937,9 @@ 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);
-        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);
-#endif /* CONFIG_VNC_TLS */
-#ifdef CONFIG_VNC_SASL
-        vnc_sasl_client_cleanup(vs);
-#endif /* CONFIG_VNC_SASL */
-        audio_del(vs);
-
-        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)
-            dcl->idle = 1;
-
-        default_allocator.free_displaysurface(vs->server.ds);
-        qemu_free(vs->guest.ds);
-        qemu_free(vs);
+        VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
+                  ret, ret < 0 ? last_errno : 0);
+        vnc_disconnect_start(vs);
 
         return 0;
     }
@@ -931,7 +949,8 @@ int vnc_client_io_error(VncState *vs, int ret, int last_errno)
 
 void vnc_client_error(VncState *vs)
 {
-    vnc_client_io_error(vs, -1, EINVAL);
+    VNC_DEBUG("Closing down client sock: protocol error\n");
+    vnc_disconnect_start(vs);
 }
 
 
@@ -965,7 +984,7 @@ long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
         }
     } else
 #endif /* CONFIG_VNC_TLS */
-        ret = send(vs->csock, data, datalen, 0);
+        ret = send(vs->csock, (const void *)data, datalen, 0);
     VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
     return vnc_client_io_error(vs, ret, socket_error());
 }
@@ -1070,7 +1089,7 @@ long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
         }
     } else
 #endif /* CONFIG_VNC_TLS */
-        ret = recv(vs->csock, data, datalen, 0);
+        ret = recv(vs->csock, (void *)data, datalen, 0);
     VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
     return vnc_client_io_error(vs, ret, socket_error());
 }
@@ -1114,16 +1133,21 @@ void vnc_client_read(void *opaque)
     else
 #endif /* CONFIG_VNC_SASL */
         ret = vnc_client_read_plain(vs);
-    if (!ret)
+    if (!ret) {
+        if (vs->csock == -1)
+            vnc_disconnect_finish(vs);
         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)
+        if (vs->csock == -1) {
+            vnc_disconnect_finish(vs);
             return;
+        }
 
         if (!ret) {
             memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
@@ -1138,7 +1162,7 @@ void vnc_write(VncState *vs, const void *data, size_t len)
 {
     buffer_reserve(&vs->output, len);
 
-    if (buffer_empty(&vs->output)) {
+    if (vs->csock != -1 && buffer_empty(&vs->output)) {
         qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
     }
 
@@ -1179,7 +1203,7 @@ void vnc_write_u8(VncState *vs, uint8_t value)
 
 void vnc_flush(VncState *vs)
 {
-    if (vs->output.offset)
+    if (vs->csock != -1 && vs->output.offset)
         vnc_client_write(vs);
 }
 
@@ -1337,6 +1361,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
     } else {
         /* QEMU console emulation */
         if (down) {
+            int numlock = vs->modifiers_state[0x45];
             switch (keycode) {
             case 0x2a:                          /* Left Shift */
             case 0x36:                          /* Right Shift */
@@ -1346,41 +1371,83 @@ 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;
+
+            case 0x47:
+                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
+                break;
+            case 0x48:
+                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
+                break;
+            case 0x49:
+                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
+                break;
+            case 0x4b:
+                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
+                break;
+            case 0x4c:
+                kbd_put_keysym('5');
+                break;
+            case 0x4d:
+                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
+                break;
+            case 0x4f:
+                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
+                break;
+            case 0x50:
+                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
+                break;
+            case 0x51:
+                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
+                break;
+            case 0x52:
+                kbd_put_keysym('0');
+                break;
+            case 0x53:
+                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
+                break;
+
+            case 0xb5:
+                kbd_put_keysym('/');
+                break;
+            case 0x37:
+                kbd_put_keysym('*');
+                break;
+            case 0x4a:
+                kbd_put_keysym('-');
+                break;
+            case 0x4e:
+                kbd_put_keysym('+');
+                break;
+            case 0x9c:
+                kbd_put_keysym('\n');
+                break;
+
             default:
                 kbd_put_keysym(sym);
                 break;
@@ -1425,8 +1492,8 @@ static void framebuffer_update_request(VncState *vs, int incremental,
 
     int i;
     vs->need_update = 1;
-    vs->force_update = 1;
     if (!incremental) {
+        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);
@@ -2013,11 +2080,13 @@ 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);
-    vnc_update_client(vs);
     reset_keys(vs);
 
     vs->next = vd->clients;
     vd->clients = vs;
+
+    vnc_update_client(vs);
+    /* vs might be free()ed here */
 }
 
 static void vnc_listen_read(void *opaque)
@@ -2037,9 +2106,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;
@@ -2104,6 +2172,13 @@ int vnc_display_password(DisplayState *ds, const char *password)
     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;