Commit 753b4053311ff1437d99726970b1e7e6bf38249b
1 parent
880fec5d
Support multiple VNC clients (Brian Kress)
Change structure associated with a display from VncState to a new structure VncDisplay. Remove client specific fields from VncDisplay. Remove display specific fields from VncState. Maintain a linked list of VncStates per VncDisplay structure, update as necessary. When updates/resizes/copies come in from the hardware, dispatch to all clients. Signed-off-by: Brian Kress <kressb@moose.net> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6621 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
172 additions
and
135 deletions
vnc.c
... | ... | @@ -90,12 +90,35 @@ typedef void VncSendHextileTile(VncState *vs, |
90 | 90 | |
91 | 91 | #define VNC_AUTH_CHALLENGE_SIZE 16 |
92 | 92 | |
93 | +typedef struct VncDisplay VncDisplay; | |
94 | + | |
95 | +struct VncDisplay | |
96 | +{ | |
97 | + int lsock; | |
98 | + DisplayState *ds; | |
99 | + VncState *clients; | |
100 | + kbd_layout_t *kbd_layout; | |
101 | + | |
102 | + char *display; | |
103 | + char *password; | |
104 | + int auth; | |
105 | +#ifdef CONFIG_VNC_TLS | |
106 | + int subauth; | |
107 | + int x509verify; | |
108 | + | |
109 | + char *x509cacert; | |
110 | + char *x509cacrl; | |
111 | + char *x509cert; | |
112 | + char *x509key; | |
113 | +#endif | |
114 | +}; | |
115 | + | |
93 | 116 | struct VncState |
94 | 117 | { |
95 | 118 | QEMUTimer *timer; |
96 | - int lsock; | |
97 | 119 | int csock; |
98 | 120 | DisplayState *ds; |
121 | + VncDisplay *vd; | |
99 | 122 | int need_update; |
100 | 123 | uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS]; |
101 | 124 | char *old_data; |
... | ... | @@ -111,18 +134,6 @@ struct VncState |
111 | 134 | int major; |
112 | 135 | int minor; |
113 | 136 | |
114 | - char *display; | |
115 | - char *password; | |
116 | - int auth; | |
117 | -#ifdef CONFIG_VNC_TLS | |
118 | - int subauth; | |
119 | - int x509verify; | |
120 | - | |
121 | - char *x509cacert; | |
122 | - char *x509cacrl; | |
123 | - char *x509cert; | |
124 | - char *x509key; | |
125 | -#endif | |
126 | 137 | char challenge[VNC_AUTH_CHALLENGE_SIZE]; |
127 | 138 | |
128 | 139 | #ifdef CONFIG_VNC_TLS |
... | ... | @@ -132,7 +143,6 @@ struct VncState |
132 | 143 | |
133 | 144 | Buffer output; |
134 | 145 | Buffer input; |
135 | - kbd_layout_t *kbd_layout; | |
136 | 146 | /* current output mode information */ |
137 | 147 | VncWritePixels *write_pixels; |
138 | 148 | VncSendHextileTile *send_hextile_tile; |
... | ... | @@ -149,21 +159,23 @@ struct VncState |
149 | 159 | Buffer zlib; |
150 | 160 | Buffer zlib_tmp; |
151 | 161 | z_stream zlib_stream[4]; |
162 | + | |
163 | + VncState *next; | |
152 | 164 | }; |
153 | 165 | |
154 | -static VncState *vnc_state; /* needed for info vnc */ | |
166 | +static VncDisplay *vnc_display; /* needed for info vnc */ | |
155 | 167 | static DisplayChangeListener *dcl; |
156 | 168 | |
157 | 169 | void do_info_vnc(void) |
158 | 170 | { |
159 | - if (vnc_state == NULL || vnc_state->display == NULL) | |
171 | + if (vnc_display == NULL || vnc_display->display == NULL) | |
160 | 172 | term_printf("VNC server disabled\n"); |
161 | 173 | else { |
162 | 174 | term_printf("VNC server active on: "); |
163 | - term_print_filename(vnc_state->display); | |
175 | + term_print_filename(vnc_display->display); | |
164 | 176 | term_printf("\n"); |
165 | 177 | |
166 | - if (vnc_state->csock == -1) | |
178 | + if (vnc_display->clients == NULL) | |
167 | 179 | term_printf("No client connected\n"); |
168 | 180 | else |
169 | 181 | term_printf("Client connected\n"); |
... | ... | @@ -190,7 +202,7 @@ static void vnc_flush(VncState *vs); |
190 | 202 | static void vnc_update_client(void *opaque); |
191 | 203 | static void vnc_client_read(void *opaque); |
192 | 204 | |
193 | -static void vnc_colordepth(DisplayState *ds); | |
205 | +static void vnc_colordepth(VncState *vs); | |
194 | 206 | |
195 | 207 | static inline void vnc_set_bit(uint32_t *d, int k) |
196 | 208 | { |
... | ... | @@ -233,9 +245,8 @@ static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2, |
233 | 245 | return 0; |
234 | 246 | } |
235 | 247 | |
236 | -static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) | |
248 | +static void vnc_update(VncState *vs, int x, int y, int w, int h) | |
237 | 249 | { |
238 | - VncState *vs = ds->opaque; | |
239 | 250 | int i; |
240 | 251 | |
241 | 252 | h += y; |
... | ... | @@ -257,6 +268,16 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) |
257 | 268 | vnc_set_bit(vs->dirty_row[y], (x + i) / 16); |
258 | 269 | } |
259 | 270 | |
271 | +static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) | |
272 | +{ | |
273 | + VncDisplay *vd = ds->opaque; | |
274 | + VncState *vs = vd->clients; | |
275 | + while (vs != NULL) { | |
276 | + vnc_update(vs, x, y, w, h); | |
277 | + vs = vs->next; | |
278 | + } | |
279 | +} | |
280 | + | |
260 | 281 | static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, |
261 | 282 | int32_t encoding) |
262 | 283 | { |
... | ... | @@ -301,10 +322,11 @@ static void buffer_append(Buffer *buffer, const void *data, size_t len) |
301 | 322 | buffer->offset += len; |
302 | 323 | } |
303 | 324 | |
304 | -static void vnc_dpy_resize(DisplayState *ds) | |
325 | +static void vnc_resize(VncState *vs) | |
305 | 326 | { |
327 | + DisplayState *ds = vs->ds; | |
328 | + | |
306 | 329 | int size_changed; |
307 | - VncState *vs = ds->opaque; | |
308 | 330 | |
309 | 331 | vs->old_data = qemu_realloc(vs->old_data, ds_get_linesize(ds) * ds_get_height(ds)); |
310 | 332 | |
... | ... | @@ -315,7 +337,7 @@ static void vnc_dpy_resize(DisplayState *ds) |
315 | 337 | |
316 | 338 | if (ds_get_bytes_per_pixel(ds) != vs->serverds.pf.bytes_per_pixel) |
317 | 339 | console_color_init(ds); |
318 | - vnc_colordepth(ds); | |
340 | + vnc_colordepth(vs); | |
319 | 341 | size_changed = ds_get_width(ds) != vs->serverds.width || |
320 | 342 | ds_get_height(ds) != vs->serverds.height; |
321 | 343 | vs->serverds = *(ds->surface); |
... | ... | @@ -334,6 +356,16 @@ static void vnc_dpy_resize(DisplayState *ds) |
334 | 356 | memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds)); |
335 | 357 | } |
336 | 358 | |
359 | +static void vnc_dpy_resize(DisplayState *ds) | |
360 | +{ | |
361 | + VncDisplay *vd = ds->opaque; | |
362 | + VncState *vs = vd->clients; | |
363 | + while (vs != NULL) { | |
364 | + vnc_resize(vs); | |
365 | + vs = vs->next; | |
366 | + } | |
367 | +} | |
368 | + | |
337 | 369 | /* fastest code */ |
338 | 370 | static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size) |
339 | 371 | { |
... | ... | @@ -599,10 +631,8 @@ static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) |
599 | 631 | } |
600 | 632 | } |
601 | 633 | |
602 | -static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) | |
634 | +static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h) | |
603 | 635 | { |
604 | - VncState *vs = ds->opaque; | |
605 | - | |
606 | 636 | vnc_update_client(vs); |
607 | 637 | |
608 | 638 | vnc_write_u8(vs, 0); /* msg id */ |
... | ... | @@ -614,6 +644,19 @@ static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_ |
614 | 644 | vnc_flush(vs); |
615 | 645 | } |
616 | 646 | |
647 | +static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) | |
648 | +{ | |
649 | + VncDisplay *vd = ds->opaque; | |
650 | + VncState *vs = vd->clients; | |
651 | + while (vs != NULL) { | |
652 | + if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) | |
653 | + vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h); | |
654 | + else /* TODO */ | |
655 | + vnc_update(vs, dst_x, dst_y, w, h); | |
656 | + vs = vs->next; | |
657 | + } | |
658 | +} | |
659 | + | |
617 | 660 | static int find_dirty_height(VncState *vs, int y, int last_x, int x) |
618 | 661 | { |
619 | 662 | int h; |
... | ... | @@ -632,7 +675,6 @@ static int find_dirty_height(VncState *vs, int y, int last_x, int x) |
632 | 675 | static void vnc_update_client(void *opaque) |
633 | 676 | { |
634 | 677 | VncState *vs = opaque; |
635 | - | |
636 | 678 | if (vs->need_update && vs->csock != -1) { |
637 | 679 | int y; |
638 | 680 | uint8_t *row; |
... | ... | @@ -725,14 +767,6 @@ static void vnc_update_client(void *opaque) |
725 | 767 | |
726 | 768 | } |
727 | 769 | |
728 | -static int vnc_listen_poll(void *opaque) | |
729 | -{ | |
730 | - VncState *vs = opaque; | |
731 | - if (vs->csock == -1) | |
732 | - return 1; | |
733 | - return 0; | |
734 | -} | |
735 | - | |
736 | 770 | /* audio */ |
737 | 771 | static void audio_capture_notify(void *opaque, audcnotification_e cmd) |
738 | 772 | { |
... | ... | @@ -817,19 +851,35 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno) |
817 | 851 | VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0); |
818 | 852 | qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); |
819 | 853 | closesocket(vs->csock); |
820 | - vs->csock = -1; | |
821 | - dcl->idle = 1; | |
822 | - buffer_reset(&vs->input); | |
823 | - buffer_reset(&vs->output); | |
824 | - vs->need_update = 0; | |
854 | + qemu_del_timer(vs->timer); | |
855 | + qemu_free_timer(vs->timer); | |
856 | + if (vs->input.buffer) qemu_free(vs->input.buffer); | |
857 | + if (vs->output.buffer) qemu_free(vs->output.buffer); | |
825 | 858 | #ifdef CONFIG_VNC_TLS |
826 | 859 | if (vs->tls_session) { |
827 | 860 | gnutls_deinit(vs->tls_session); |
828 | 861 | vs->tls_session = NULL; |
829 | 862 | } |
830 | - vs->wiremode = VNC_WIREMODE_CLEAR; | |
831 | 863 | #endif /* CONFIG_VNC_TLS */ |
832 | 864 | audio_del(vs); |
865 | + | |
866 | + VncState *p, *parent = NULL; | |
867 | + for (p = vs->vd->clients; p != NULL; p = p->next) { | |
868 | + if (p == vs) { | |
869 | + if (parent) | |
870 | + parent->next = p->next; | |
871 | + else | |
872 | + vs->vd->clients = p->next; | |
873 | + break; | |
874 | + } | |
875 | + parent = p; | |
876 | + } | |
877 | + if (!vs->vd->clients) | |
878 | + dcl->idle = 1; | |
879 | + | |
880 | + qemu_free(vs->old_data); | |
881 | + qemu_free(vs); | |
882 | + | |
833 | 883 | return 0; |
834 | 884 | } |
835 | 885 | return ret; |
... | ... | @@ -1095,8 +1145,8 @@ static void reset_keys(VncState *vs) |
1095 | 1145 | |
1096 | 1146 | static void press_key(VncState *vs, int keysym) |
1097 | 1147 | { |
1098 | - kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) & 0x7f); | |
1099 | - kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80); | |
1148 | + kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f); | |
1149 | + kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80); | |
1100 | 1150 | } |
1101 | 1151 | |
1102 | 1152 | static void do_key_event(VncState *vs, int down, int keycode, int sym) |
... | ... | @@ -1129,12 +1179,12 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) |
1129 | 1179 | break; |
1130 | 1180 | } |
1131 | 1181 | |
1132 | - if (keycode_is_keypad(vs->kbd_layout, keycode)) { | |
1182 | + if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) { | |
1133 | 1183 | /* If the numlock state needs to change then simulate an additional |
1134 | 1184 | keypress before sending this one. This will happen if the user |
1135 | 1185 | toggles numlock away from the VNC window. |
1136 | 1186 | */ |
1137 | - if (keysym_is_numlock(vs->kbd_layout, sym & 0xFFFF)) { | |
1187 | + if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) { | |
1138 | 1188 | if (!vs->modifiers_state[0x45]) { |
1139 | 1189 | vs->modifiers_state[0x45] = 1; |
1140 | 1190 | press_key(vs, 0xff7f); |
... | ... | @@ -1207,7 +1257,7 @@ static void key_event(VncState *vs, int down, uint32_t sym) |
1207 | 1257 | if (sym >= 'A' && sym <= 'Z' && is_graphic_console()) |
1208 | 1258 | sym = sym - 'A' + 'a'; |
1209 | 1259 | |
1210 | - keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF); | |
1260 | + keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF); | |
1211 | 1261 | do_key_event(vs, down, keycode, sym); |
1212 | 1262 | } |
1213 | 1263 | |
... | ... | @@ -1279,7 +1329,6 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) |
1279 | 1329 | vs->tight_compression = 9; |
1280 | 1330 | vs->tight_quality = 9; |
1281 | 1331 | vs->absolute = -1; |
1282 | - dcl->dpy_copy = NULL; | |
1283 | 1332 | |
1284 | 1333 | for (i = n_encodings - 1; i >= 0; i--) { |
1285 | 1334 | enc = encodings[i]; |
... | ... | @@ -1288,7 +1337,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) |
1288 | 1337 | vs->vnc_encoding = enc; |
1289 | 1338 | break; |
1290 | 1339 | case VNC_ENCODING_COPYRECT: |
1291 | - dcl->dpy_copy = vnc_copy; | |
1340 | + vs->features |= VNC_FEATURE_COPYRECT_MASK; | |
1292 | 1341 | break; |
1293 | 1342 | case VNC_ENCODING_HEXTILE: |
1294 | 1343 | vs->features |= VNC_FEATURE_HEXTILE_MASK; |
... | ... | @@ -1432,17 +1481,15 @@ static void vnc_dpy_setdata(DisplayState *ds) |
1432 | 1481 | /* We don't have to do anything */ |
1433 | 1482 | } |
1434 | 1483 | |
1435 | -static void vnc_colordepth(DisplayState *ds) | |
1484 | +static void vnc_colordepth(VncState *vs) | |
1436 | 1485 | { |
1437 | - struct VncState *vs = ds->opaque; | |
1438 | - | |
1439 | - if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_WMVI)) { | |
1486 | + if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) { | |
1440 | 1487 | /* Sending a WMVi message to notify the client*/ |
1441 | 1488 | vnc_write_u8(vs, 0); /* msg id */ |
1442 | 1489 | vnc_write_u8(vs, 0); |
1443 | 1490 | vnc_write_u16(vs, 1); /* number of rects */ |
1444 | - vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds), | |
1445 | - VNC_ENCODING_WMVi); | |
1491 | + vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), | |
1492 | + ds_get_height(vs->ds), VNC_ENCODING_WMVi); | |
1446 | 1493 | pixel_format_message(vs); |
1447 | 1494 | vnc_flush(vs); |
1448 | 1495 | } else { |
... | ... | @@ -1626,7 +1673,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) |
1626 | 1673 | int i, j, pwlen; |
1627 | 1674 | unsigned char key[8]; |
1628 | 1675 | |
1629 | - if (!vs->password || !vs->password[0]) { | |
1676 | + if (!vs->vd->password || !vs->vd->password[0]) { | |
1630 | 1677 | VNC_DEBUG("No password configured on server"); |
1631 | 1678 | vnc_write_u32(vs, 1); /* Reject auth */ |
1632 | 1679 | if (vs->minor >= 8) { |
... | ... | @@ -1642,9 +1689,9 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) |
1642 | 1689 | memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE); |
1643 | 1690 | |
1644 | 1691 | /* Calculate the expected challenge response */ |
1645 | - pwlen = strlen(vs->password); | |
1692 | + pwlen = strlen(vs->vd->password); | |
1646 | 1693 | for (i=0; i<sizeof(key); i++) |
1647 | - key[i] = i<pwlen ? vs->password[i] : 0; | |
1694 | + key[i] = i<pwlen ? vs->vd->password[i] : 0; | |
1648 | 1695 | deskey(key, EN0); |
1649 | 1696 | for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8) |
1650 | 1697 | des(response+j, response+j); |
... | ... | @@ -1733,15 +1780,15 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *v |
1733 | 1780 | gnutls_certificate_credentials_t x509_cred; |
1734 | 1781 | int ret; |
1735 | 1782 | |
1736 | - if (!vs->x509cacert) { | |
1783 | + if (!vs->vd->x509cacert) { | |
1737 | 1784 | VNC_DEBUG("No CA x509 certificate specified\n"); |
1738 | 1785 | return NULL; |
1739 | 1786 | } |
1740 | - if (!vs->x509cert) { | |
1787 | + if (!vs->vd->x509cert) { | |
1741 | 1788 | VNC_DEBUG("No server x509 certificate specified\n"); |
1742 | 1789 | return NULL; |
1743 | 1790 | } |
1744 | - if (!vs->x509key) { | |
1791 | + if (!vs->vd->x509key) { | |
1745 | 1792 | VNC_DEBUG("No server private key specified\n"); |
1746 | 1793 | return NULL; |
1747 | 1794 | } |
... | ... | @@ -1751,7 +1798,7 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *v |
1751 | 1798 | return NULL; |
1752 | 1799 | } |
1753 | 1800 | if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, |
1754 | - vs->x509cacert, | |
1801 | + vs->vd->x509cacert, | |
1755 | 1802 | GNUTLS_X509_FMT_PEM)) < 0) { |
1756 | 1803 | VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret)); |
1757 | 1804 | gnutls_certificate_free_credentials(x509_cred); |
... | ... | @@ -1759,17 +1806,17 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *v |
1759 | 1806 | } |
1760 | 1807 | |
1761 | 1808 | if ((ret = gnutls_certificate_set_x509_key_file (x509_cred, |
1762 | - vs->x509cert, | |
1763 | - vs->x509key, | |
1809 | + vs->vd->x509cert, | |
1810 | + vs->vd->x509key, | |
1764 | 1811 | GNUTLS_X509_FMT_PEM)) < 0) { |
1765 | 1812 | VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret)); |
1766 | 1813 | gnutls_certificate_free_credentials(x509_cred); |
1767 | 1814 | return NULL; |
1768 | 1815 | } |
1769 | 1816 | |
1770 | - if (vs->x509cacrl) { | |
1817 | + if (vs->vd->x509cacrl) { | |
1771 | 1818 | if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, |
1772 | - vs->x509cacrl, | |
1819 | + vs->vd->x509cacrl, | |
1773 | 1820 | GNUTLS_X509_FMT_PEM)) < 0) { |
1774 | 1821 | VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret)); |
1775 | 1822 | gnutls_certificate_free_credentials(x509_cred); |
... | ... | @@ -1863,7 +1910,7 @@ static int vnc_validate_certificate(struct VncState *vs) |
1863 | 1910 | |
1864 | 1911 | static int start_auth_vencrypt_subauth(VncState *vs) |
1865 | 1912 | { |
1866 | - switch (vs->subauth) { | |
1913 | + switch (vs->vd->subauth) { | |
1867 | 1914 | case VNC_AUTH_VENCRYPT_TLSNONE: |
1868 | 1915 | case VNC_AUTH_VENCRYPT_X509NONE: |
1869 | 1916 | VNC_DEBUG("Accept TLS auth none\n"); |
... | ... | @@ -1877,7 +1924,7 @@ static int start_auth_vencrypt_subauth(VncState *vs) |
1877 | 1924 | return start_auth_vnc(vs); |
1878 | 1925 | |
1879 | 1926 | default: /* Should not be possible, but just in case */ |
1880 | - VNC_DEBUG("Reject auth %d\n", vs->auth); | |
1927 | + VNC_DEBUG("Reject auth %d\n", vs->vd->auth); | |
1881 | 1928 | vnc_write_u8(vs, 1); |
1882 | 1929 | if (vs->minor >= 8) { |
1883 | 1930 | static const char err[] = "Unsupported authentication type"; |
... | ... | @@ -1909,7 +1956,7 @@ static int vnc_continue_handshake(struct VncState *vs) { |
1909 | 1956 | return -1; |
1910 | 1957 | } |
1911 | 1958 | |
1912 | - if (vs->x509verify) { | |
1959 | + if (vs->vd->x509verify) { | |
1913 | 1960 | if (vnc_validate_certificate(vs) < 0) { |
1914 | 1961 | VNC_DEBUG("Client verification failed\n"); |
1915 | 1962 | vnc_client_error(vs); |
... | ... | @@ -1934,9 +1981,9 @@ static void vnc_handshake_io(void *opaque) { |
1934 | 1981 | } |
1935 | 1982 | |
1936 | 1983 | #define NEED_X509_AUTH(vs) \ |
1937 | - ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ | |
1938 | - (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ | |
1939 | - (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN) | |
1984 | + ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ | |
1985 | + (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ | |
1986 | + (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN) | |
1940 | 1987 | |
1941 | 1988 | |
1942 | 1989 | static int vnc_start_tls(struct VncState *vs) { |
... | ... | @@ -2000,7 +2047,7 @@ static int vnc_start_tls(struct VncState *vs) { |
2000 | 2047 | vnc_client_error(vs); |
2001 | 2048 | return -1; |
2002 | 2049 | } |
2003 | - if (vs->x509verify) { | |
2050 | + if (vs->vd->x509verify) { | |
2004 | 2051 | VNC_DEBUG("Requesting a client certificate\n"); |
2005 | 2052 | gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST); |
2006 | 2053 | } |
... | ... | @@ -2035,7 +2082,7 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len |
2035 | 2082 | { |
2036 | 2083 | int auth = read_u32(data, 0); |
2037 | 2084 | |
2038 | - if (auth != vs->subauth) { | |
2085 | + if (auth != vs->vd->subauth) { | |
2039 | 2086 | VNC_DEBUG("Rejecting auth %d\n", auth); |
2040 | 2087 | vnc_write_u8(vs, 0); /* Reject auth */ |
2041 | 2088 | vnc_flush(vs); |
... | ... | @@ -2070,10 +2117,10 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len |
2070 | 2117 | vnc_flush(vs); |
2071 | 2118 | vnc_client_error(vs); |
2072 | 2119 | } else { |
2073 | - VNC_DEBUG("Sending allowed auth %d\n", vs->subauth); | |
2120 | + VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth); | |
2074 | 2121 | vnc_write_u8(vs, 0); /* Accept version */ |
2075 | 2122 | vnc_write_u8(vs, 1); /* Number of sub-auths */ |
2076 | - vnc_write_u32(vs, vs->subauth); /* The supported auth */ | |
2123 | + vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */ | |
2077 | 2124 | vnc_flush(vs); |
2078 | 2125 | vnc_read_when(vs, protocol_client_vencrypt_auth, 4); |
2079 | 2126 | } |
... | ... | @@ -2095,7 +2142,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len) |
2095 | 2142 | { |
2096 | 2143 | /* We only advertise 1 auth scheme at a time, so client |
2097 | 2144 | * must pick the one we sent. Verify this */ |
2098 | - if (data[0] != vs->auth) { /* Reject auth */ | |
2145 | + if (data[0] != vs->vd->auth) { /* Reject auth */ | |
2099 | 2146 | VNC_DEBUG("Reject auth %d\n", (int)data[0]); |
2100 | 2147 | vnc_write_u32(vs, 1); |
2101 | 2148 | if (vs->minor >= 8) { |
... | ... | @@ -2106,7 +2153,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len) |
2106 | 2153 | vnc_client_error(vs); |
2107 | 2154 | } else { /* Accept requested auth */ |
2108 | 2155 | VNC_DEBUG("Client requested auth %d\n", (int)data[0]); |
2109 | - switch (vs->auth) { | |
2156 | + switch (vs->vd->auth) { | |
2110 | 2157 | case VNC_AUTH_NONE: |
2111 | 2158 | VNC_DEBUG("Accept auth none\n"); |
2112 | 2159 | if (vs->minor >= 8) { |
... | ... | @@ -2127,7 +2174,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len) |
2127 | 2174 | #endif /* CONFIG_VNC_TLS */ |
2128 | 2175 | |
2129 | 2176 | default: /* Should not be possible, but just in case */ |
2130 | - VNC_DEBUG("Reject auth %d\n", vs->auth); | |
2177 | + VNC_DEBUG("Reject auth %d\n", vs->vd->auth); | |
2131 | 2178 | vnc_write_u8(vs, 1); |
2132 | 2179 | if (vs->minor >= 8) { |
2133 | 2180 | static const char err[] = "Authentication failed"; |
... | ... | @@ -2172,26 +2219,26 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len) |
2172 | 2219 | vs->minor = 3; |
2173 | 2220 | |
2174 | 2221 | if (vs->minor == 3) { |
2175 | - if (vs->auth == VNC_AUTH_NONE) { | |
2222 | + if (vs->vd->auth == VNC_AUTH_NONE) { | |
2176 | 2223 | VNC_DEBUG("Tell client auth none\n"); |
2177 | - vnc_write_u32(vs, vs->auth); | |
2224 | + vnc_write_u32(vs, vs->vd->auth); | |
2178 | 2225 | vnc_flush(vs); |
2179 | 2226 | vnc_read_when(vs, protocol_client_init, 1); |
2180 | - } else if (vs->auth == VNC_AUTH_VNC) { | |
2227 | + } else if (vs->vd->auth == VNC_AUTH_VNC) { | |
2181 | 2228 | VNC_DEBUG("Tell client VNC auth\n"); |
2182 | - vnc_write_u32(vs, vs->auth); | |
2229 | + vnc_write_u32(vs, vs->vd->auth); | |
2183 | 2230 | vnc_flush(vs); |
2184 | 2231 | start_auth_vnc(vs); |
2185 | 2232 | } else { |
2186 | - VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth); | |
2233 | + VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth); | |
2187 | 2234 | vnc_write_u32(vs, VNC_AUTH_INVALID); |
2188 | 2235 | vnc_flush(vs); |
2189 | 2236 | vnc_client_error(vs); |
2190 | 2237 | } |
2191 | 2238 | } else { |
2192 | - VNC_DEBUG("Telling client we support auth %d\n", vs->auth); | |
2239 | + VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth); | |
2193 | 2240 | vnc_write_u8(vs, 1); /* num auth */ |
2194 | - vnc_write_u8(vs, vs->auth); | |
2241 | + vnc_write_u8(vs, vs->vd->auth); | |
2195 | 2242 | vnc_read_when(vs, protocol_client_auth, 1); |
2196 | 2243 | vnc_flush(vs); |
2197 | 2244 | } |
... | ... | @@ -2199,55 +2246,67 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len) |
2199 | 2246 | return 0; |
2200 | 2247 | } |
2201 | 2248 | |
2202 | -static void vnc_connect(VncState *vs) | |
2249 | +static void vnc_connect(VncDisplay *vd, int csock) | |
2203 | 2250 | { |
2204 | - VNC_DEBUG("New client on socket %d\n", vs->csock); | |
2251 | + VncState *vs = qemu_mallocz(sizeof(VncState)); | |
2252 | + vs->csock = csock; | |
2253 | + | |
2254 | + VNC_DEBUG("New client on socket %d\n", csock); | |
2205 | 2255 | dcl->idle = 0; |
2206 | 2256 | socket_set_nonblock(vs->csock); |
2207 | 2257 | qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); |
2258 | + | |
2259 | + vs->vd = vd; | |
2260 | + vs->ds = vd->ds; | |
2261 | + vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs); | |
2262 | + vs->last_x = -1; | |
2263 | + vs->last_y = -1; | |
2264 | + | |
2265 | + vs->as.freq = 44100; | |
2266 | + vs->as.nchannels = 2; | |
2267 | + vs->as.fmt = AUD_FMT_S16; | |
2268 | + vs->as.endianness = 0; | |
2269 | + | |
2270 | + vnc_resize(vs); | |
2208 | 2271 | vnc_write(vs, "RFB 003.008\n", 12); |
2209 | 2272 | vnc_flush(vs); |
2210 | 2273 | vnc_read_when(vs, protocol_version, 12); |
2211 | 2274 | memset(vs->old_data, 0, ds_get_linesize(vs->ds) * ds_get_height(vs->ds)); |
2212 | 2275 | memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); |
2213 | - vs->features = 0; | |
2214 | - dcl->dpy_copy = NULL; | |
2215 | 2276 | vnc_update_client(vs); |
2216 | 2277 | reset_keys(vs); |
2278 | + | |
2279 | + vs->next = vd->clients; | |
2280 | + vd->clients = vs; | |
2217 | 2281 | } |
2218 | 2282 | |
2219 | 2283 | static void vnc_listen_read(void *opaque) |
2220 | 2284 | { |
2221 | - VncState *vs = opaque; | |
2285 | + VncDisplay *vs = opaque; | |
2222 | 2286 | struct sockaddr_in addr; |
2223 | 2287 | socklen_t addrlen = sizeof(addr); |
2224 | 2288 | |
2225 | 2289 | /* Catch-up */ |
2226 | 2290 | vga_hw_update(); |
2227 | 2291 | |
2228 | - vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); | |
2229 | - if (vs->csock != -1) { | |
2230 | - vnc_connect(vs); | |
2292 | + int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); | |
2293 | + if (csock != -1) { | |
2294 | + vnc_connect(vs, csock); | |
2231 | 2295 | } |
2232 | 2296 | } |
2233 | 2297 | |
2234 | 2298 | void vnc_display_init(DisplayState *ds) |
2235 | 2299 | { |
2236 | - VncState *vs; | |
2300 | + VncDisplay *vs; | |
2237 | 2301 | |
2238 | 2302 | vs = qemu_mallocz(sizeof(VncState)); |
2239 | 2303 | dcl = qemu_mallocz(sizeof(DisplayChangeListener)); |
2240 | 2304 | |
2241 | 2305 | ds->opaque = vs; |
2242 | 2306 | dcl->idle = 1; |
2243 | - vnc_state = vs; | |
2244 | - vs->display = NULL; | |
2245 | - vs->password = NULL; | |
2307 | + vnc_display = vs; | |
2246 | 2308 | |
2247 | 2309 | vs->lsock = -1; |
2248 | - vs->csock = -1; | |
2249 | - vs->last_x = -1; | |
2250 | - vs->last_y = -1; | |
2251 | 2310 | |
2252 | 2311 | vs->ds = ds; |
2253 | 2312 | |
... | ... | @@ -2259,22 +2318,15 @@ void vnc_display_init(DisplayState *ds) |
2259 | 2318 | if (!vs->kbd_layout) |
2260 | 2319 | exit(1); |
2261 | 2320 | |
2262 | - vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs); | |
2263 | - | |
2321 | + dcl->dpy_copy = vnc_dpy_copy; | |
2264 | 2322 | dcl->dpy_update = vnc_dpy_update; |
2265 | 2323 | dcl->dpy_resize = vnc_dpy_resize; |
2266 | 2324 | dcl->dpy_setdata = vnc_dpy_setdata; |
2267 | - dcl->dpy_refresh = NULL; | |
2268 | 2325 | register_displaychangelistener(ds, dcl); |
2269 | - | |
2270 | - vs->as.freq = 44100; | |
2271 | - vs->as.nchannels = 2; | |
2272 | - vs->as.fmt = AUD_FMT_S16; | |
2273 | - vs->as.endianness = 0; | |
2274 | 2326 | } |
2275 | 2327 | |
2276 | 2328 | #ifdef CONFIG_VNC_TLS |
2277 | -static int vnc_set_x509_credential(VncState *vs, | |
2329 | +static int vnc_set_x509_credential(VncDisplay *vs, | |
2278 | 2330 | const char *certdir, |
2279 | 2331 | const char *filename, |
2280 | 2332 | char **cred, |
... | ... | @@ -2305,7 +2357,7 @@ static int vnc_set_x509_credential(VncState *vs, |
2305 | 2357 | return 0; |
2306 | 2358 | } |
2307 | 2359 | |
2308 | -static int vnc_set_x509_credential_dir(VncState *vs, | |
2360 | +static int vnc_set_x509_credential_dir(VncDisplay *vs, | |
2309 | 2361 | const char *certdir) |
2310 | 2362 | { |
2311 | 2363 | if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0) |
... | ... | @@ -2331,7 +2383,7 @@ static int vnc_set_x509_credential_dir(VncState *vs, |
2331 | 2383 | |
2332 | 2384 | void vnc_display_close(DisplayState *ds) |
2333 | 2385 | { |
2334 | - VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; | |
2386 | + VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; | |
2335 | 2387 | |
2336 | 2388 | if (!vs) |
2337 | 2389 | return; |
... | ... | @@ -2344,32 +2396,16 @@ void vnc_display_close(DisplayState *ds) |
2344 | 2396 | close(vs->lsock); |
2345 | 2397 | vs->lsock = -1; |
2346 | 2398 | } |
2347 | - if (vs->csock != -1) { | |
2348 | - qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); | |
2349 | - closesocket(vs->csock); | |
2350 | - vs->csock = -1; | |
2351 | - buffer_reset(&vs->input); | |
2352 | - buffer_reset(&vs->output); | |
2353 | - vs->need_update = 0; | |
2354 | -#ifdef CONFIG_VNC_TLS | |
2355 | - if (vs->tls_session) { | |
2356 | - gnutls_deinit(vs->tls_session); | |
2357 | - vs->tls_session = NULL; | |
2358 | - } | |
2359 | - vs->wiremode = VNC_WIREMODE_CLEAR; | |
2360 | -#endif /* CONFIG_VNC_TLS */ | |
2361 | - } | |
2362 | 2399 | vs->auth = VNC_AUTH_INVALID; |
2363 | 2400 | #ifdef CONFIG_VNC_TLS |
2364 | 2401 | vs->subauth = VNC_AUTH_INVALID; |
2365 | 2402 | vs->x509verify = 0; |
2366 | 2403 | #endif |
2367 | - audio_del(vs); | |
2368 | 2404 | } |
2369 | 2405 | |
2370 | 2406 | int vnc_display_password(DisplayState *ds, const char *password) |
2371 | 2407 | { |
2372 | - VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; | |
2408 | + VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; | |
2373 | 2409 | |
2374 | 2410 | if (vs->password) { |
2375 | 2411 | qemu_free(vs->password); |
... | ... | @@ -2385,7 +2421,7 @@ int vnc_display_password(DisplayState *ds, const char *password) |
2385 | 2421 | |
2386 | 2422 | int vnc_display_open(DisplayState *ds, const char *display) |
2387 | 2423 | { |
2388 | - VncState *vs = ds ? (VncState *)ds->opaque : vnc_state; | |
2424 | + VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; | |
2389 | 2425 | const char *options; |
2390 | 2426 | int password = 0; |
2391 | 2427 | int reverse = 0; |
... | ... | @@ -2394,7 +2430,7 @@ int vnc_display_open(DisplayState *ds, const char *display) |
2394 | 2430 | int tls = 0, x509 = 0; |
2395 | 2431 | #endif |
2396 | 2432 | |
2397 | - if (!vnc_state) | |
2433 | + if (!vnc_display) | |
2398 | 2434 | return -1; |
2399 | 2435 | vnc_display_close(ds); |
2400 | 2436 | if (strcmp(display, "none") == 0) |
... | ... | @@ -2499,9 +2535,9 @@ int vnc_display_open(DisplayState *ds, const char *display) |
2499 | 2535 | vs->display = NULL; |
2500 | 2536 | return -1; |
2501 | 2537 | } else { |
2502 | - vs->csock = vs->lsock; | |
2538 | + int csock = vs->lsock; | |
2503 | 2539 | vs->lsock = -1; |
2504 | - vnc_connect(vs); | |
2540 | + vnc_connect(vs, csock); | |
2505 | 2541 | } |
2506 | 2542 | return 0; |
2507 | 2543 | |
... | ... | @@ -2523,6 +2559,5 @@ int vnc_display_open(DisplayState *ds, const char *display) |
2523 | 2559 | vs->display = dpy; |
2524 | 2560 | } |
2525 | 2561 | } |
2526 | - | |
2527 | - return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs); | |
2562 | + return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs); | |
2528 | 2563 | } | ... | ... |
vnc.h
... | ... | @@ -101,6 +101,7 @@ enum { |
101 | 101 | #define VNC_FEATURE_WMVI 3 |
102 | 102 | #define VNC_FEATURE_TIGHT 4 |
103 | 103 | #define VNC_FEATURE_ZLIB 5 |
104 | +#define VNC_FEATURE_COPYRECT 6 | |
104 | 105 | |
105 | 106 | #define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE) |
106 | 107 | #define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE) |
... | ... | @@ -108,5 +109,6 @@ enum { |
108 | 109 | #define VNC_FEATURE_WMVI_MASK (1 << VNC_FEATURE_WMVI) |
109 | 110 | #define VNC_FEATURE_TIGHT_MASK (1 << VNC_FEATURE_TIGHT) |
110 | 111 | #define VNC_FEATURE_ZLIB_MASK (1 << VNC_FEATURE_ZLIB) |
112 | +#define VNC_FEATURE_COPYRECT_MASK (1 << VNC_FEATURE_COPYRECT) | |
111 | 113 | |
112 | 114 | #endif /* __VNCTIGHT_H */ | ... | ... |