Diff for /qemu/vnc.c between versions 1.1.1.7 and 1.1.1.8

version 1.1.1.7, 2018/04/24 17:21:01 version 1.1.1.8, 2018/04/24 17:34:49
Line 29 Line 29
 #include "qemu_socket.h"  #include "qemu_socket.h"
 #include "qemu-timer.h"  #include "qemu-timer.h"
 #include "acl.h"  #include "acl.h"
   #include "qemu-objects.h"
   
 #define VNC_REFRESH_INTERVAL (1000 / 30)  #define VNC_REFRESH_INTERVAL_BASE 30
   #define VNC_REFRESH_INTERVAL_INC  50
   #define VNC_REFRESH_INTERVAL_MAX  2000
   
 #include "vnc_keysym.h"  #include "vnc_keysym.h"
 #include "d3des.h"  #include "d3des.h"
Line 97  char *vnc_socket_remote_addr(const char  Line 100  char *vnc_socket_remote_addr(const char 
     return addr_to_string(format, &sa, salen);      return addr_to_string(format, &sa, salen);
 }  }
   
   static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa,
                             socklen_t salen)
   {
       char host[NI_MAXHOST];
       char serv[NI_MAXSERV];
       int err;
   
       if ((err = getnameinfo((struct sockaddr *)sa, salen,
                              host, sizeof(host),
                              serv, sizeof(serv),
                              NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
           VNC_DEBUG("Cannot resolve address %d: %s\n",
                     err, gai_strerror(err));
           return -1;
       }
   
       qdict_put(qdict, "host", qstring_from_str(host));
       qdict_put(qdict, "service", qstring_from_str(serv));
   
       return 0;
   }
   
   static int vnc_qdict_local_addr(QDict *qdict, int fd)
   {
       struct sockaddr_storage sa;
       socklen_t salen;
   
       salen = sizeof(sa);
       if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
           return -1;
       }
   
       return put_addr_qdict(qdict, &sa, salen);
   }
   
   static int vnc_qdict_remote_addr(QDict *qdict, int fd)
   {
       struct sockaddr_storage sa;
       socklen_t salen;
   
       salen = sizeof(sa);
       if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
           return -1;
       }
   
       return put_addr_qdict(qdict, &sa, salen);
   }
   
 static const char *vnc_auth_name(VncDisplay *vd) {  static const char *vnc_auth_name(VncDisplay *vd) {
     switch (vd->auth) {      switch (vd->auth) {
     case VNC_AUTH_INVALID:      case VNC_AUTH_INVALID:
Line 148  static const char *vnc_auth_name(VncDisp Line 199  static const char *vnc_auth_name(VncDisp
     return "unknown";      return "unknown";
 }  }
   
 static void do_info_vnc_client(Monitor *mon, VncState *client)  static QDict *do_info_vnc_client(Monitor *mon, VncState *client)
 {  {
     char *clientAddr =      QDict *qdict;
         vnc_socket_remote_addr("     address: %s:%s\n",  
                                client->csock);  
     if (!clientAddr)  
         return;  
   
     monitor_printf(mon, "Client:\n");      qdict = qdict_new();
     monitor_printf(mon, "%s", clientAddr);      if (vnc_qdict_remote_addr(qdict, client->csock) < 0) {
     free(clientAddr);          QDECREF(qdict);
           return NULL;
       }
   
 #ifdef CONFIG_VNC_TLS  #ifdef CONFIG_VNC_TLS
     if (client->tls.session &&      if (client->tls.session &&
         client->tls.dname)          client->tls.dname) {
         monitor_printf(mon, "  x509 dname: %s\n", client->tls.dname);          qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname));
     else      }
         monitor_printf(mon, "  x509 dname: none\n");  
 #endif  #endif
 #ifdef CONFIG_VNC_SASL  #ifdef CONFIG_VNC_SASL
     if (client->sasl.conn &&      if (client->sasl.conn &&
         client->sasl.username)          client->sasl.username) {
         monitor_printf(mon, "    username: %s\n", client->sasl.username);          qdict_put(qdict, "username", qstring_from_str(client->sasl.username));
     else      }
         monitor_printf(mon, "    username: none\n");  
 #endif  #endif
   
       return qdict;
 }  }
   
 void do_info_vnc(Monitor *mon)  static void info_vnc_iter(QObject *obj, void *opaque)
 {  {
     if (vnc_display == NULL || vnc_display->display == NULL) {      QDict *client;
       Monitor *mon = opaque;
   
       client = qobject_to_qdict(obj);
       monitor_printf(mon, "Client:\n");
       monitor_printf(mon, "     address: %s:%s\n",
                      qdict_get_str(client, "host"),
                      qdict_get_str(client, "service"));
   
   #ifdef CONFIG_VNC_TLS
       monitor_printf(mon, "  x509_dname: %s\n",
           qdict_haskey(client, "x509_dname") ?
           qdict_get_str(client, "x509_dname") : "none");
   #endif
   #ifdef CONFIG_VNC_SASL
       monitor_printf(mon, "    username: %s\n",
           qdict_haskey(client, "username") ?
           qdict_get_str(client, "username") : "none");
   #endif
   }
   
   void do_info_vnc_print(Monitor *mon, const QObject *data)
   {
       QDict *server;
       QList *clients;
   
       server = qobject_to_qdict(data);
       if (strcmp(qdict_get_str(server, "status"), "disabled") == 0) {
         monitor_printf(mon, "Server: disabled\n");          monitor_printf(mon, "Server: disabled\n");
     } else {          return;
         char *serverAddr = vnc_socket_local_addr("     address: %s:%s\n",      }
                                                  vnc_display->lsock);  
   
         if (!serverAddr)      monitor_printf(mon, "Server:\n");
             return;      monitor_printf(mon, "     address: %s:%s\n",
                      qdict_get_str(server, "host"),
                      qdict_get_str(server, "service"));
       monitor_printf(mon, "        auth: %s\n",
           qdict_haskey(server, "auth") ? qdict_get_str(server, "auth") : "none");
   
       clients = qdict_get_qlist(server, "clients");
       if (qlist_empty(clients)) {
           monitor_printf(mon, "Client: none\n");
       } else {
           qlist_iter(clients, info_vnc_iter, mon);
       }
   }
   
         monitor_printf(mon, "Server:\n");  /**
         monitor_printf(mon, "%s", serverAddr);   * do_info_vnc(): Show VNC server information
         free(serverAddr);   *
         monitor_printf(mon, "        auth: %s\n", vnc_auth_name(vnc_display));   * Return a QDict with server information. Connected clients are returned
    * as a QList of QDicts.
    *
    * The main QDict contains the following:
    *
    * - "status": "disabled" or "enabled"
    * - "host": server's IP address
    * - "service": server's port number
    * - "auth": authentication method (optional)
    * - "clients": a QList of all connected clients
    *
    * Clients are described by a QDict, with the following information:
    *
    * - "host": client's IP address
    * - "service": client's port number
    * - "x509_dname": TLS dname (optional)
    * - "username": SASL username (optional)
    *
    * Example:
    *
    * { "status": "enabled", "host": "0.0.0.0", "service": "50402", "auth": "vnc",
    *   "clients": [ { "host": "127.0.0.1", "service": "50401" } ] }
    */
   void do_info_vnc(Monitor *mon, QObject **ret_data)
   {
       if (vnc_display == NULL || vnc_display->display == NULL) {
           *ret_data = qobject_from_jsonf("{ 'status': 'disabled' }");
       } else {
           QDict *qdict;
           QList *clist;
   
           clist = qlist_new();
         if (vnc_display->clients) {          if (vnc_display->clients) {
             VncState *client = vnc_display->clients;              VncState *client = vnc_display->clients;
             while (client) {              while (client) {
                 do_info_vnc_client(mon, client);                  qdict = do_info_vnc_client(mon, client);
                   if (qdict)
                       qlist_append(clist, qdict);
                 client = client->next;                  client = client->next;
             }              }
         } else {          }
             monitor_printf(mon, "Client: none\n");  
           *ret_data = qobject_from_jsonf("{ 'status': 'enabled', 'clients': %p }",
                                          QOBJECT(clist));
           assert(*ret_data != NULL);
   
           qdict = qobject_to_qdict(*ret_data);
   
           if (vnc_display->auth != VNC_AUTH_NONE) {
               qdict_put(qdict, "auth",
                         qstring_from_str(vnc_auth_name(vnc_display)));
           }
   
           if (vnc_qdict_local_addr(qdict, vnc_display->lsock) < 0) {
               qobject_decref(*ret_data);
               *ret_data = NULL;
         }          }
     }      }
 }  }
Line 215  static inline uint32_t vnc_has_feature(V Line 348  static inline uint32_t vnc_has_feature(V
    3) resolutions > 1024     3) resolutions > 1024
 */  */
   
 static void vnc_update_client(void *opaque);  static int vnc_update_client(VncState *vs, int has_dirty);
 static void vnc_disconnect_start(VncState *vs);  static void vnc_disconnect_start(VncState *vs);
 static void vnc_disconnect_finish(VncState *vs);  static void vnc_disconnect_finish(VncState *vs);
   static void vnc_init_timer(VncDisplay *vd);
   static void vnc_remove_timer(VncDisplay *vd);
   
 static void vnc_colordepth(VncState *vs);  static void vnc_colordepth(VncState *vs);
   static void framebuffer_update_request(VncState *vs, int incremental,
                                          int x_position, int y_position,
                                          int w, int h);
   static void vnc_refresh(void *opaque);
   static int vnc_refresh_server_surface(VncDisplay *vd);
   
 static inline void vnc_set_bit(uint32_t *d, int k)  static inline void vnc_set_bit(uint32_t *d, int k)
 {  {
Line 262  static inline int vnc_and_bits(const uin Line 402  static inline int vnc_and_bits(const uin
     return 0;      return 0;
 }  }
   
 static void vnc_update(VncState *vs, int x, int y, int w, int h)  static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
 {  {
     struct VncSurface *s = &vs->guest;  
     int i;      int i;
       VncDisplay *vd = ds->opaque;
       struct VncSurface *s = &vd->guest;
   
     h += y;      h += y;
   
Line 286  static void vnc_update(VncState *vs, int Line 427  static void vnc_update(VncState *vs, int
             vnc_set_bit(s->dirty[y], (x + 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)  
 {  
     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,  static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
                                    int32_t encoding)                                     int32_t encoding)
 {  {
Line 340  void buffer_append(Buffer *buffer, const Line 471  void buffer_append(Buffer *buffer, const
     buffer->offset += len;      buffer->offset += len;
 }  }
   
 static void vnc_resize(VncState *vs)  static void vnc_dpy_resize(DisplayState *ds)
 {  {
     DisplayState *ds = vs->ds;  
     int size_changed;      int size_changed;
       VncDisplay *vd = ds->opaque;
       VncState *vs = vd->clients;
   
       /* server surface */
       if (!vd->server)
           vd->server = qemu_mallocz(sizeof(*vd->server));
       if (vd->server->data)
           qemu_free(vd->server->data);
       *(vd->server) = *(ds->surface);
       vd->server->data = qemu_mallocz(vd->server->linesize *
                                       vd->server->height);
   
     /* guest surface */      /* guest surface */
     if (!vs->guest.ds)      if (!vd->guest.ds)
         vs->guest.ds = qemu_mallocz(sizeof(*vs->guest.ds));          vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
     if (ds_get_bytes_per_pixel(ds) != vs->guest.ds->pf.bytes_per_pixel)      if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
         console_color_init(ds);          console_color_init(ds);
     vnc_colordepth(vs);      size_changed = ds_get_width(ds) != vd->guest.ds->width ||
     size_changed = ds_get_width(ds) != vs->guest.ds->width ||                     ds_get_height(ds) != vd->guest.ds->height;
                    ds_get_height(ds) != vs->guest.ds->height;      *(vd->guest.ds) = *(ds->surface);
     *(vs->guest.ds) = *(ds->surface);      memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
     if (size_changed) {  
         if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_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_get_width(ds), ds_get_height(ds),  
                                    VNC_ENCODING_DESKTOPRESIZE);  
             vnc_flush(vs);  
         }  
     }  
     memset(vs->guest.dirty, 0xFF, sizeof(vs->guest.dirty));  
   
     /* 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)  
 {  
     VncDisplay *vd = ds->opaque;  
     VncState *vs = vd->clients;  
     while (vs != NULL) {      while (vs != NULL) {
         vnc_resize(vs);          vnc_colordepth(vs);
           if (size_changed) {
               if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_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_get_width(ds), ds_get_height(ds),
                           VNC_ENCODING_DESKTOPRESIZE);
                   vnc_flush(vs);
               }
           }
           memset(vs->dirty, 0xFF, sizeof(vs->dirty));
         vs = vs->next;          vs = vs->next;
     }      }
 }  }
Line 397  static void vnc_write_pixels_copy(VncSta Line 523  static void vnc_write_pixels_copy(VncSta
 static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)  static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
 {  {
     uint8_t r, g, b;      uint8_t r, g, b;
       VncDisplay *vd = vs->vd;
   
     r = ((((v & vs->server.ds->pf.rmask) >> vs->server.ds->pf.rshift) << vs->clientds.pf.rbits) >>      r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >>
         vs->server.ds->pf.rbits);          vd->server->pf.rbits);
     g = ((((v & vs->server.ds->pf.gmask) >> vs->server.ds->pf.gshift) << vs->clientds.pf.gbits) >>      g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >>
         vs->server.ds->pf.gbits);          vd->server->pf.gbits);
     b = ((((v & vs->server.ds->pf.bmask) >> vs->server.ds->pf.bshift) << vs->clientds.pf.bbits) >>      b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >>
         vs->server.ds->pf.bbits);          vd->server->pf.bbits);
     v = (r << vs->clientds.pf.rshift) |      v = (r << vs->clientds.pf.rshift) |
         (g << vs->clientds.pf.gshift) |          (g << vs->clientds.pf.gshift) |
         (b << vs->clientds.pf.bshift);          (b << vs->clientds.pf.bshift);
Line 440  static void vnc_convert_pixel(VncState * Line 567  static void vnc_convert_pixel(VncState *
 static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)  static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
 {  {
     uint8_t buf[4];      uint8_t buf[4];
       VncDisplay *vd = vs->vd;
   
     if (vs->server.ds->pf.bytes_per_pixel == 4) {      if (vd->server->pf.bytes_per_pixel == 4) {
         uint32_t *pixels = pixels1;          uint32_t *pixels = pixels1;
         int n, i;          int n, i;
         n = size >> 2;          n = size >> 2;
Line 449  static void vnc_write_pixels_generic(Vnc Line 577  static void vnc_write_pixels_generic(Vnc
             vnc_convert_pixel(vs, buf, pixels[i]);              vnc_convert_pixel(vs, buf, pixels[i]);
             vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);              vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
         }          }
     } else if (vs->server.ds->pf.bytes_per_pixel == 2) {      } else if (vd->server->pf.bytes_per_pixel == 2) {
         uint16_t *pixels = pixels1;          uint16_t *pixels = pixels1;
         int n, i;          int n, i;
         n = size >> 1;          n = size >> 1;
Line 457  static void vnc_write_pixels_generic(Vnc Line 585  static void vnc_write_pixels_generic(Vnc
             vnc_convert_pixel(vs, buf, pixels[i]);              vnc_convert_pixel(vs, buf, pixels[i]);
             vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);              vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
         }          }
     } else if (vs->server.ds->pf.bytes_per_pixel == 1) {      } else if (vd->server->pf.bytes_per_pixel == 1) {
         uint8_t *pixels = pixels1;          uint8_t *pixels = pixels1;
         int n, i;          int n, i;
         n = size;          n = size;
Line 474  static void send_framebuffer_update_raw( Line 602  static void send_framebuffer_update_raw(
 {  {
     int i;      int i;
     uint8_t *row;      uint8_t *row;
       VncDisplay *vd = vs->vd;
   
     row = vs->server.ds->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);      row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
     for (i = 0; i < h; i++) {      for (i = 0; i < h; i++) {
         vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));          vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
         row += ds_get_linesize(vs->ds);          row += ds_get_linesize(vs->ds);
Line 523  static void send_framebuffer_update_hext Line 652  static void send_framebuffer_update_hext
     int i, j;      int i, j;
     int has_fg, has_bg;      int has_fg, has_bg;
     uint8_t *last_fg, *last_bg;      uint8_t *last_fg, *last_bg;
       VncDisplay *vd = vs->vd;
   
     last_fg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);      last_fg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
     last_bg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);      last_bg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
     has_fg = has_bg = 0;      has_fg = has_bg = 0;
     for (j = y; j < (y + h); j += 16) {      for (j = y; j < (y + h); j += 16) {
         for (i = x; i < (x + w); i += 16) {          for (i = x; i < (x + w); i += 16) {
Line 539  static void send_framebuffer_update_hext Line 669  static void send_framebuffer_update_hext
   
 }  }
   
   #define ZALLOC_ALIGNMENT 16
   
   static void *zalloc(void *x, unsigned items, unsigned size)
   {
       void *p;
   
       size *= items;
       size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
   
       p = qemu_mallocz(size);
   
       return (p);
   }
   
   static void zfree(void *x, void *addr)
   {
       qemu_free(addr);
   }
   
 static void vnc_zlib_init(VncState *vs)  static void vnc_zlib_init(VncState *vs)
 {  {
     int i;      int i;
Line 573  static int vnc_zlib_stop(VncState *vs, i Line 722  static int vnc_zlib_stop(VncState *vs, i
   
         VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);          VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
         VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);          VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
         zstream->zalloc = Z_NULL;          zstream->zalloc = zalloc;
         zstream->zfree = Z_NULL;          zstream->zfree = zfree;
   
         err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,          err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
                            MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);                             MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
Line 654  static void send_framebuffer_update(VncS Line 803  static void send_framebuffer_update(VncS
   
 static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_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)
 {  {
     uint8_t *src_row;  
     uint8_t *dst_row;  
     int y,pitch,depth;  
   
     /* send bitblit op to the vnc client */      /* send bitblit op to the vnc client */
     vnc_write_u8(vs, 0);  /* msg id */      vnc_write_u8(vs, 0);  /* msg id */
     vnc_write_u8(vs, 0);      vnc_write_u8(vs, 0);
Line 666  static void vnc_copy(VncState *vs, int s Line 811  static void vnc_copy(VncState *vs, int s
     vnc_write_u16(vs, src_x);      vnc_write_u16(vs, src_x);
     vnc_write_u16(vs, src_y);      vnc_write_u16(vs, src_y);
     vnc_flush(vs);      vnc_flush(vs);
   
     /* do bitblit op on the local surface too */  
     pitch = ds_get_linesize(vs->ds);  
     depth = ds_get_bytes_per_pixel(vs->ds);  
     src_row = vs->server.ds->data + pitch * src_y + depth * src_x;  
     dst_row = vs->server.ds->data + pitch * dst_y + depth * dst_x;  
     if (dst_y > src_y) {  
         /* copy backwards */  
         src_row += pitch * (h-1);  
         dst_row += pitch * (h-1);  
         pitch = -pitch;  
     }  
     for (y = 0; y < h; y++) {  
         memmove(dst_row, src_row, w * depth);  
         src_row += pitch;  
         dst_row += pitch;  
     }  
 }  }
   
 static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)  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;      VncDisplay *vd = ds->opaque;
     VncState *vs, *vn;      VncState *vs, *vn;
       uint8_t *src_row;
       uint8_t *dst_row;
       int i,x,y,pitch,depth,inc,w_lim,s;
       int cmp_bytes;
   
       vnc_refresh_server_surface(vd);
     for (vs = vd->clients; vs != NULL; vs = vn) {      for (vs = vd->clients; vs != NULL; vs = vn) {
         vn = vs->next;          vn = vs->next;
         if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {          if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
             vs->force_update = 1;              vs->force_update = 1;
             vnc_update_client(vs);              vnc_update_client(vs, 1);
             /* vs might be free()ed here */              /* vs might be free()ed here */
         }          }
     }      }
   
       /* do bitblit op on the local surface too */
       pitch = ds_get_linesize(vd->ds);
       depth = ds_get_bytes_per_pixel(vd->ds);
       src_row = vd->server->data + pitch * src_y + depth * src_x;
       dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
       y = dst_y;
       inc = 1;
       if (dst_y > src_y) {
           /* copy backwards */
           src_row += pitch * (h-1);
           dst_row += pitch * (h-1);
           pitch = -pitch;
           y = dst_y + h - 1;
           inc = -1;
       }
       w_lim = w - (16 - (dst_x % 16));
       if (w_lim < 0)
           w_lim = w;
       else
           w_lim = w - (w_lim % 16);
       for (i = 0; i < h; i++) {
           for (x = 0; x <= w_lim;
                   x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
               if (x == w_lim) {
                   if ((s = w - w_lim) == 0)
                       break;
               } else if (!x) {
                   s = (16 - (dst_x % 16));
                   s = MIN(s, w_lim);
               } else {
                   s = 16;
               }
               cmp_bytes = s * depth;
               if (memcmp(src_row, dst_row, cmp_bytes) == 0)
                   continue;
               memmove(dst_row, src_row, cmp_bytes);
               vs = vd->clients;
               while (vs != NULL) {
                   if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
                       vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16));
                   vs = vs->next;
               }
           }
           src_row += pitch - w * depth;
           dst_row += pitch - w * depth;
           y += inc;
       }
   
     for (vs = vd->clients; vs != NULL; vs = vs->next) {      for (vs = vd->clients; vs != NULL; vs = vs->next) {
         if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))          if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
             vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);              vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
         else /* TODO */  
             vnc_update(vs, dst_x, dst_y, w, h);  
     }      }
 }  }
   
 static int find_and_clear_dirty_height(struct VncSurface *s,  static int find_and_clear_dirty_height(struct VncState *vs,
                                        int y, int last_x, int x)                                         int y, int last_x, int x)
 {  {
     int h;      int h;
       VncDisplay *vd = vs->vd;
   
     for (h = 1; h < (s->ds->height - y); h++) {      for (h = 1; h < (vd->server->height - y); h++) {
         int tmp_x;          int tmp_x;
         if (!vnc_get_bit(s->dirty[y + h], last_x))          if (!vnc_get_bit(vs->dirty[y + h], last_x))
             break;              break;
         for (tmp_x = last_x; tmp_x < x; tmp_x++)          for (tmp_x = last_x; tmp_x < x; tmp_x++)
             vnc_clear_bit(s->dirty[y + h], tmp_x);              vnc_clear_bit(vs->dirty[y + h], tmp_x);
     }      }
   
     return h;      return h;
 }  }
   
 static void vnc_update_client(void *opaque)  static int vnc_update_client(VncState *vs, int has_dirty)
 {  {
     VncState *vs = opaque;  
     if (vs->need_update && vs->csock != -1) {      if (vs->need_update && vs->csock != -1) {
           VncDisplay *vd = vs->vd;
         int y;          int y;
         uint8_t *guest_row;  
         uint8_t *server_row;  
         int cmp_bytes;  
         uint32_t width_mask[VNC_DIRTY_WORDS];  
         int n_rectangles;          int n_rectangles;
         int saved_offset;          int saved_offset;
         int has_dirty = 0;  
   
         if (vs->output.offset && !vs->audio_cap && !vs->force_update) {          if (vs->output.offset && !vs->audio_cap && !vs->force_update)
             /* kernel send buffers are full -> drop frames to throttle */              /* kernel send buffers are full -> drop frames to throttle */
             qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);              return 0;
             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) {          if (!has_dirty && !vs->audio_cap && !vs->force_update)
             qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);              return 0;
             return;  
         }  
   
         /*          /*
          * Send screen updates to the vnc client using the server           * Send screen updates to the vnc client using the server
Line 795  static void vnc_update_client(void *opaq Line 930  static void vnc_update_client(void *opaq
         saved_offset = vs->output.offset;          saved_offset = vs->output.offset;
         vnc_write_u16(vs, 0);          vnc_write_u16(vs, 0);
   
         for (y = 0; y < vs->server.ds->height; y++) {          for (y = 0; y < vd->server->height; y++) {
             int x;              int x;
             int last_x = -1;              int last_x = -1;
             for (x = 0; x < vs->server.ds->width / 16; x++) {              for (x = 0; x < vd->server->width / 16; x++) {
                 if (vnc_get_bit(vs->server.dirty[y], x)) {                  if (vnc_get_bit(vs->dirty[y], x)) {
                     if (last_x == -1) {                      if (last_x == -1) {
                         last_x = x;                          last_x = x;
                     }                      }
                     vnc_clear_bit(vs->server.dirty[y], x);                      vnc_clear_bit(vs->dirty[y], x);
                 } else {                  } else {
                     if (last_x != -1) {                      if (last_x != -1) {
                         int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);                          int h = find_and_clear_dirty_height(vs, y, last_x, x);
                         send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);                          send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
                         n_rectangles++;                          n_rectangles++;
                     }                      }
Line 814  static void vnc_update_client(void *opaq Line 949  static void vnc_update_client(void *opaq
                 }                  }
             }              }
             if (last_x != -1) {              if (last_x != -1) {
                 int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);                  int h = find_and_clear_dirty_height(vs, y, last_x, x);
                 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);                  send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
                 n_rectangles++;                  n_rectangles++;
             }              }
Line 823  static void vnc_update_client(void *opaq Line 958  static void vnc_update_client(void *opaq
         vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;          vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
         vnc_flush(vs);          vnc_flush(vs);
         vs->force_update = 0;          vs->force_update = 0;
           return n_rectangles;
     }      }
   
     if (vs->csock != -1) {      if (vs->csock == -1)
         qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);  
     } else {  
         vnc_disconnect_finish(vs);          vnc_disconnect_finish(vs);
     }  
   
       return 0;
 }  }
   
 /* audio */  /* audio */
Line 911  static void vnc_disconnect_start(VncStat Line 1044  static void vnc_disconnect_start(VncStat
   
 static void vnc_disconnect_finish(VncState *vs)  static void vnc_disconnect_finish(VncState *vs)
 {  {
     qemu_del_timer(vs->timer);      if (vs->input.buffer) {
     qemu_free_timer(vs->timer);          qemu_free(vs->input.buffer);
     if (vs->input.buffer) qemu_free(vs->input.buffer);          vs->input.buffer = NULL;
     if (vs->output.buffer) qemu_free(vs->output.buffer);      }
       if (vs->output.buffer) {
           qemu_free(vs->output.buffer);
           vs->output.buffer = NULL;
       }
 #ifdef CONFIG_VNC_TLS  #ifdef CONFIG_VNC_TLS
     vnc_tls_client_cleanup(vs);      vnc_tls_client_cleanup(vs);
 #endif /* CONFIG_VNC_TLS */  #endif /* CONFIG_VNC_TLS */
Line 937  static void vnc_disconnect_finish(VncSta Line 1074  static void vnc_disconnect_finish(VncSta
     if (!vs->vd->clients)      if (!vs->vd->clients)
         dcl->idle = 1;          dcl->idle = 1;
   
     qemu_free(vs->server.ds->data);      vnc_remove_timer(vs->vd);
     qemu_free(vs->server.ds);  
     qemu_free(vs->guest.ds);  
     qemu_free(vs);      qemu_free(vs);
 }  }
   
Line 1373  static void do_key_event(VncState *vs, i Line 1508  static void do_key_event(VncState *vs, i
         }          }
     }      }
   
       if ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z')) {
           /* If the capslock state needs to change then simulate an additional
              keypress before sending this one.  This will happen if the user
              toggles capslock away from the VNC window.
           */
           int uppercase = !!(sym >= 'A' && sym <= 'Z');
           int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
           int capslock = !!(vs->modifiers_state[0x3a]);
           if (capslock) {
               if (uppercase == shift) {
                   vs->modifiers_state[0x3a] = 0;
                   press_key(vs, 0xffe5);
               }
           } else {
               if (uppercase != shift) {
                   vs->modifiers_state[0x3a] = 1;
                   press_key(vs, 0xffe5);
               }
           }
       }
   
     if (is_graphic_console()) {      if (is_graphic_console()) {
         if (keycode & 0x80)          if (keycode & 0x80)
             kbd_put_keycode(0xe0);              kbd_put_keycode(0xe0);
Line 1481  static void do_key_event(VncState *vs, i Line 1637  static void do_key_event(VncState *vs, i
 static void key_event(VncState *vs, int down, uint32_t sym)  static void key_event(VncState *vs, int down, uint32_t sym)
 {  {
     int keycode;      int keycode;
       int lsym = sym;
   
     if (sym >= 'A' && sym <= 'Z' && is_graphic_console())      if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) {
         sym = sym - 'A' + 'a';          lsym = lsym - 'A' + 'a';
       }
   
     keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF);      keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF);
     do_key_event(vs, down, keycode, sym);      do_key_event(vs, down, keycode, sym);
 }  }
   
Line 1517  static void framebuffer_update_request(V Line 1675  static void framebuffer_update_request(V
     if (!incremental) {      if (!incremental) {
         vs->force_update = 1;          vs->force_update = 1;
         for (i = 0; i < h; i++) {          for (i = 0; i < h; i++) {
             vnc_set_bits(vs->guest.dirty[y_position + i],              vnc_set_bits(vs->dirty[y_position + i],
                          (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);  
             vnc_set_bits(vs->server.dirty[y_position + i],  
                          (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);                           (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
         }          }
     }      }
Line 1648  static void set_pixel_format(VncState *v Line 1804  static void set_pixel_format(VncState *v
         return;          return;
     }      }
   
     vs->clientds = *(vs->guest.ds);      vs->clientds = *(vs->vd->guest.ds);
     vs->clientds.pf.rmax = red_max;      vs->clientds.pf.rmax = red_max;
     count_bits(vs->clientds.pf.rbits, red_max);      count_bits(vs->clientds.pf.rbits, red_max);
     vs->clientds.pf.rshift = red_shift;      vs->clientds.pf.rshift = red_shift;
Line 1678  static void pixel_format_message (VncSta Line 1834  static void pixel_format_message (VncSta
     vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */      vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
     vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */      vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
   
 #ifdef WORDS_BIGENDIAN  #ifdef HOST_WORDS_BIGENDIAN
     vnc_write_u8(vs, 1);             /* big-endian-flag */      vnc_write_u8(vs, 1);             /* big-endian-flag */
 #else  #else
     vnc_write_u8(vs, 0);             /* big-endian-flag */      vnc_write_u8(vs, 0);             /* big-endian-flag */
Line 1728  static int protocol_client_msg(VncState  Line 1884  static int protocol_client_msg(VncState 
 {  {
     int i;      int i;
     uint16_t limit;      uint16_t limit;
       VncDisplay *vd = vs->vd;
   
       if (data[0] > 3) {
           vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
           if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval))
               qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
       }
   
     switch (data[0]) {      switch (data[0]) {
     case 0:      case 0:
Line 2077  static int protocol_version(VncState *vs Line 2240  static int protocol_version(VncState *vs
     return 0;      return 0;
 }  }
   
   static int vnc_refresh_server_surface(VncDisplay *vd)
   {
       int y;
       uint8_t *guest_row;
       uint8_t *server_row;
       int cmp_bytes;
       uint32_t width_mask[VNC_DIRTY_WORDS];
       VncState *vs = NULL;
       int has_dirty = 0;
   
       /*
        * 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(vd->ds) / 16), VNC_DIRTY_WORDS);
       cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
       guest_row  = vd->guest.ds->data;
       server_row = vd->server->data;
       for (y = 0; y < vd->guest.ds->height; y++) {
           if (vnc_and_bits(vd->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 < vd->guest.ds->width;
                       x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
                   if (!vnc_get_bit(vd->guest.dirty[y], (x / 16)))
                       continue;
                   vnc_clear_bit(vd->guest.dirty[y], (x / 16));
                   if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
                       continue;
                   memcpy(server_ptr, guest_ptr, cmp_bytes);
                   vs = vd->clients;
                   while (vs != NULL) {
                       vnc_set_bit(vs->dirty[y], (x / 16));
                       vs = vs->next;
                   }
                   has_dirty++;
               }
           }
           guest_row  += ds_get_linesize(vd->ds);
           server_row += ds_get_linesize(vd->ds);
       }
       return has_dirty;
   }
   
   static void vnc_refresh(void *opaque)
   {
       VncDisplay *vd = opaque;
       VncState *vs = NULL;
       int has_dirty = 0, rects = 0;
   
       vga_hw_update();
   
       has_dirty = vnc_refresh_server_surface(vd);
   
       vs = vd->clients;
       while (vs != NULL) {
           rects += vnc_update_client(vs, has_dirty);
           vs = vs->next;
       }
   
       if (has_dirty && rects) {
           vd->timer_interval /= 2;
           if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE)
               vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
       } else {
           vd->timer_interval += VNC_REFRESH_INTERVAL_INC;
           if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
               vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
       }
       qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
   }
   
   static void vnc_init_timer(VncDisplay *vd)
   {
       vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
       if (vd->timer == NULL && vd->clients != NULL) {
           vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
           vnc_refresh(vd);
       }
   }
   
   static void vnc_remove_timer(VncDisplay *vd)
   {
       if (vd->timer != NULL && vd->clients == NULL) {
           qemu_del_timer(vd->timer);
           qemu_free_timer(vd->timer);
           vd->timer = NULL;
       }
   }
   
 static void vnc_connect(VncDisplay *vd, int csock)  static void vnc_connect(VncDisplay *vd, int csock)
 {  {
     VncState *vs = qemu_mallocz(sizeof(VncState));      VncState *vs = qemu_mallocz(sizeof(VncState));
Line 2089  static void vnc_connect(VncDisplay *vd,  Line 2348  static void vnc_connect(VncDisplay *vd, 
   
     vs->vd = vd;      vs->vd = vd;
     vs->ds = vd->ds;      vs->ds = vd->ds;
     vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);  
     vs->last_x = -1;      vs->last_x = -1;
     vs->last_y = -1;      vs->last_y = -1;
   
Line 2098  static void vnc_connect(VncDisplay *vd,  Line 2356  static void vnc_connect(VncDisplay *vd, 
     vs->as.fmt = AUD_FMT_S16;      vs->as.fmt = AUD_FMT_S16;
     vs->as.endianness = 0;      vs->as.endianness = 0;
   
     vnc_resize(vs);      vs->next = vd->clients;
       vd->clients = vs;
   
       vga_hw_update();
   
     vnc_write(vs, "RFB 003.008\n", 12);      vnc_write(vs, "RFB 003.008\n", 12);
     vnc_flush(vs);      vnc_flush(vs);
     vnc_read_when(vs, protocol_version, 12);      vnc_read_when(vs, protocol_version, 12);
     reset_keys(vs);      reset_keys(vs);
   
     vs->next = vd->clients;      vnc_init_timer(vd);
     vd->clients = vs;  
   
     vnc_update_client(vs);  
     /* vs might be free()ed here */      /* vs might be free()ed here */
 }  }
   
Line 2120  static void vnc_listen_read(void *opaque Line 2380  static void vnc_listen_read(void *opaque
     /* Catch-up */      /* Catch-up */
     vga_hw_update();      vga_hw_update();
   
     int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);      int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
     if (csock != -1) {      if (csock != -1) {
         vnc_connect(vs, csock);          vnc_connect(vs, csock);
     }      }

Removed from v.1.1.1.7  
changed lines
  Added in v.1.1.1.8


unix.superglobalmegacorp.com