blob: 39c0d98609557141df37e4f9a96bd0b0d47c36de [file] [log] [blame]
bellard7d510b82006-05-01 10:38:19 +00001/*
2 * QEMU VNC display driver
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard7d510b82006-05-01 10:38:19 +00004 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5 * Copyright (C) 2006 Fabrice Bellard
aliguori19a490b2009-03-06 20:27:13 +00006 * Copyright (C) 2009 Red Hat, Inc
ths5fafdf22007-09-16 21:08:06 +00007 *
bellard7d510b82006-05-01 10:38:19 +00008 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
aliguori19a490b2009-03-06 20:27:13 +000027#include "vnc.h"
pbrook87ecb682007-11-17 17:14:51 +000028#include "sysemu.h"
bellard6ca957f2006-04-30 22:53:25 +000029#include "qemu_socket.h"
pbrook87ecb682007-11-17 17:14:51 +000030#include "qemu-timer.h"
aliguori76655d62009-03-06 20:27:37 +000031#include "acl.h"
bellard24236862006-04-30 21:28:36 +000032
Stefano Stabellini2430ffe2009-08-03 10:56:01 +010033#define VNC_REFRESH_INTERVAL_BASE 30
34#define VNC_REFRESH_INTERVAL_INC 50
35#define VNC_REFRESH_INTERVAL_MAX 2000
bellard24236862006-04-30 21:28:36 +000036
37#include "vnc_keysym.h"
ths70848512007-08-25 01:37:05 +000038#include "d3des.h"
39
aliguori90a1e3c2009-01-26 15:37:30 +000040#define count_bits(c, v) { \
41 for (c = 0; v; v >>= 1) \
42 { \
43 c += v & 1; \
44 } \
45}
ths8d5d2d42007-08-25 01:37:51 +000046
bellard24236862006-04-30 21:28:36 +000047
aliguori753b4052009-02-16 14:59:30 +000048static VncDisplay *vnc_display; /* needed for info vnc */
aliguori7d957bd2009-01-15 22:14:11 +000049static DisplayChangeListener *dcl;
bellarda9ce8592007-02-05 20:20:30 +000050
aliguori1ff7df12009-03-06 20:27:05 +000051static char *addr_to_string(const char *format,
52 struct sockaddr_storage *sa,
53 socklen_t salen) {
54 char *addr;
55 char host[NI_MAXHOST];
56 char serv[NI_MAXSERV];
57 int err;
aliguori457772e2009-03-13 15:03:27 +000058 size_t addrlen;
aliguori1ff7df12009-03-06 20:27:05 +000059
60 if ((err = getnameinfo((struct sockaddr *)sa, salen,
61 host, sizeof(host),
62 serv, sizeof(serv),
63 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
64 VNC_DEBUG("Cannot resolve address %d: %s\n",
65 err, gai_strerror(err));
66 return NULL;
67 }
68
aliguori457772e2009-03-13 15:03:27 +000069 /* Enough for the existing format + the 2 vars we're
Stefan Weilf425c272009-06-06 17:00:31 +020070 * substituting in. */
aliguori457772e2009-03-13 15:03:27 +000071 addrlen = strlen(format) + strlen(host) + strlen(serv);
72 addr = qemu_malloc(addrlen + 1);
73 snprintf(addr, addrlen, format, host, serv);
74 addr[addrlen] = '\0';
aliguori1ff7df12009-03-06 20:27:05 +000075
76 return addr;
77}
78
aliguori2f9606b2009-03-06 20:27:28 +000079
80char *vnc_socket_local_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +000081 struct sockaddr_storage sa;
82 socklen_t salen;
83
84 salen = sizeof(sa);
85 if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
86 return NULL;
87
88 return addr_to_string(format, &sa, salen);
89}
90
aliguori2f9606b2009-03-06 20:27:28 +000091char *vnc_socket_remote_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +000092 struct sockaddr_storage sa;
93 socklen_t salen;
94
95 salen = sizeof(sa);
96 if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
97 return NULL;
98
99 return addr_to_string(format, &sa, salen);
100}
101
102static const char *vnc_auth_name(VncDisplay *vd) {
103 switch (vd->auth) {
104 case VNC_AUTH_INVALID:
105 return "invalid";
106 case VNC_AUTH_NONE:
107 return "none";
108 case VNC_AUTH_VNC:
109 return "vnc";
110 case VNC_AUTH_RA2:
111 return "ra2";
112 case VNC_AUTH_RA2NE:
113 return "ra2ne";
114 case VNC_AUTH_TIGHT:
115 return "tight";
116 case VNC_AUTH_ULTRA:
117 return "ultra";
118 case VNC_AUTH_TLS:
119 return "tls";
120 case VNC_AUTH_VENCRYPT:
121#ifdef CONFIG_VNC_TLS
122 switch (vd->subauth) {
123 case VNC_AUTH_VENCRYPT_PLAIN:
124 return "vencrypt+plain";
125 case VNC_AUTH_VENCRYPT_TLSNONE:
126 return "vencrypt+tls+none";
127 case VNC_AUTH_VENCRYPT_TLSVNC:
128 return "vencrypt+tls+vnc";
129 case VNC_AUTH_VENCRYPT_TLSPLAIN:
130 return "vencrypt+tls+plain";
131 case VNC_AUTH_VENCRYPT_X509NONE:
132 return "vencrypt+x509+none";
133 case VNC_AUTH_VENCRYPT_X509VNC:
134 return "vencrypt+x509+vnc";
135 case VNC_AUTH_VENCRYPT_X509PLAIN:
136 return "vencrypt+x509+plain";
aliguori28a76be2009-03-06 20:27:40 +0000137 case VNC_AUTH_VENCRYPT_TLSSASL:
138 return "vencrypt+tls+sasl";
139 case VNC_AUTH_VENCRYPT_X509SASL:
140 return "vencrypt+x509+sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000141 default:
142 return "vencrypt";
143 }
144#else
145 return "vencrypt";
146#endif
aliguori2f9606b2009-03-06 20:27:28 +0000147 case VNC_AUTH_SASL:
aliguori28a76be2009-03-06 20:27:40 +0000148 return "sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000149 }
150 return "unknown";
151}
152
aliguori1ff7df12009-03-06 20:27:05 +0000153static void do_info_vnc_client(Monitor *mon, VncState *client)
154{
155 char *clientAddr =
156 vnc_socket_remote_addr(" address: %s:%s\n",
157 client->csock);
158 if (!clientAddr)
159 return;
160
161 monitor_printf(mon, "Client:\n");
162 monitor_printf(mon, "%s", clientAddr);
163 free(clientAddr);
aliguori1263b7d2009-03-06 20:27:32 +0000164
165#ifdef CONFIG_VNC_TLS
166 if (client->tls.session &&
aliguori28a76be2009-03-06 20:27:40 +0000167 client->tls.dname)
168 monitor_printf(mon, " x509 dname: %s\n", client->tls.dname);
aliguori1263b7d2009-03-06 20:27:32 +0000169 else
aliguori28a76be2009-03-06 20:27:40 +0000170 monitor_printf(mon, " x509 dname: none\n");
aliguori1263b7d2009-03-06 20:27:32 +0000171#endif
172#ifdef CONFIG_VNC_SASL
173 if (client->sasl.conn &&
aliguori28a76be2009-03-06 20:27:40 +0000174 client->sasl.username)
175 monitor_printf(mon, " username: %s\n", client->sasl.username);
aliguori1263b7d2009-03-06 20:27:32 +0000176 else
aliguori28a76be2009-03-06 20:27:40 +0000177 monitor_printf(mon, " username: none\n");
aliguori1263b7d2009-03-06 20:27:32 +0000178#endif
aliguori1ff7df12009-03-06 20:27:05 +0000179}
180
aliguori376253e2009-03-05 23:01:23 +0000181void do_info_vnc(Monitor *mon)
bellarda9ce8592007-02-05 20:20:30 +0000182{
aliguori1ff7df12009-03-06 20:27:05 +0000183 if (vnc_display == NULL || vnc_display->display == NULL) {
184 monitor_printf(mon, "Server: disabled\n");
185 } else {
186 char *serverAddr = vnc_socket_local_addr(" address: %s:%s\n",
187 vnc_display->lsock);
bellarda9ce8592007-02-05 20:20:30 +0000188
aliguori1ff7df12009-03-06 20:27:05 +0000189 if (!serverAddr)
190 return;
191
192 monitor_printf(mon, "Server:\n");
193 monitor_printf(mon, "%s", serverAddr);
194 free(serverAddr);
195 monitor_printf(mon, " auth: %s\n", vnc_auth_name(vnc_display));
196
197 if (vnc_display->clients) {
198 VncState *client = vnc_display->clients;
199 while (client) {
200 do_info_vnc_client(mon, client);
201 client = client->next;
202 }
203 } else {
204 monitor_printf(mon, "Client: none\n");
205 }
bellarda9ce8592007-02-05 20:20:30 +0000206 }
207}
208
aliguori29fa4ed2009-02-02 15:58:29 +0000209static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
210 return (vs->features & (1 << feature));
211}
212
bellard24236862006-04-30 21:28:36 +0000213/* TODO
214 1) Get the queue working for IO.
215 2) there is some weirdness when using the -S option (the screen is grey
216 and not totally invalidated
217 3) resolutions > 1024
218*/
219
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100220static int vnc_update_client(VncState *vs, int has_dirty);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200221static void vnc_disconnect_start(VncState *vs);
222static void vnc_disconnect_finish(VncState *vs);
Stefano Stabellini703bc682009-08-03 10:54:05 +0100223static void vnc_init_timer(VncDisplay *vd);
224static void vnc_remove_timer(VncDisplay *vd);
bellard24236862006-04-30 21:28:36 +0000225
aliguori753b4052009-02-16 14:59:30 +0000226static void vnc_colordepth(VncState *vs);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100227static void framebuffer_update_request(VncState *vs, int incremental,
228 int x_position, int y_position,
229 int w, int h);
230static void vnc_refresh(void *opaque);
231static int vnc_refresh_server_surface(VncDisplay *vd);
aliguori7eac3a82008-09-15 16:03:41 +0000232
bellard99589bd2006-06-13 16:35:24 +0000233static inline void vnc_set_bit(uint32_t *d, int k)
234{
235 d[k >> 5] |= 1 << (k & 0x1f);
236}
237
238static inline void vnc_clear_bit(uint32_t *d, int k)
239{
240 d[k >> 5] &= ~(1 << (k & 0x1f));
241}
242
243static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
244{
245 int j;
246
247 j = 0;
248 while (n >= 32) {
249 d[j++] = -1;
250 n -= 32;
251 }
ths5fafdf22007-09-16 21:08:06 +0000252 if (n > 0)
bellard99589bd2006-06-13 16:35:24 +0000253 d[j++] = (1 << n) - 1;
254 while (j < nb_words)
255 d[j++] = 0;
256}
257
258static inline int vnc_get_bit(const uint32_t *d, int k)
259{
260 return (d[k >> 5] >> (k & 0x1f)) & 1;
261}
262
ths5fafdf22007-09-16 21:08:06 +0000263static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
bellard99589bd2006-06-13 16:35:24 +0000264 int nb_words)
265{
266 int i;
267 for(i = 0; i < nb_words; i++) {
268 if ((d1[i] & d2[i]) != 0)
269 return 1;
270 }
271 return 0;
272}
273
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100274static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000275{
bellard24236862006-04-30 21:28:36 +0000276 int i;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100277 VncDisplay *vd = ds->opaque;
278 struct VncSurface *s = &vd->guest;
bellard24236862006-04-30 21:28:36 +0000279
280 h += y;
281
balrog0486e8a2007-12-11 22:31:32 +0000282 /* round x down to ensure the loop only spans one 16-pixel block per,
283 iteration. otherwise, if (x % 16) != 0, the last iteration may span
284 two 16-pixel blocks but we only mark the first as dirty
285 */
286 w += (x % 16);
287 x -= (x % 16);
288
aliguori6baebed2009-03-20 15:59:14 +0000289 x = MIN(x, s->ds->width);
290 y = MIN(y, s->ds->height);
291 w = MIN(x + w, s->ds->width) - x;
292 h = MIN(h, s->ds->height);
balrog788abf82008-05-20 00:07:58 +0000293
bellard24236862006-04-30 21:28:36 +0000294 for (; y < h; y++)
aliguori28a76be2009-03-06 20:27:40 +0000295 for (i = 0; i < w; i += 16)
aliguori6baebed2009-03-20 15:59:14 +0000296 vnc_set_bit(s->dirty[y], (x + i) / 16);
bellard24236862006-04-30 21:28:36 +0000297}
298
299static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
aliguori28a76be2009-03-06 20:27:40 +0000300 int32_t encoding)
bellard24236862006-04-30 21:28:36 +0000301{
302 vnc_write_u16(vs, x);
303 vnc_write_u16(vs, y);
304 vnc_write_u16(vs, w);
305 vnc_write_u16(vs, h);
306
307 vnc_write_s32(vs, encoding);
308}
309
aliguori2f9606b2009-03-06 20:27:28 +0000310void buffer_reserve(Buffer *buffer, size_t len)
aliguori89064282009-02-02 15:58:47 +0000311{
312 if ((buffer->capacity - buffer->offset) < len) {
aliguori28a76be2009-03-06 20:27:40 +0000313 buffer->capacity += (len + 1024);
314 buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
315 if (buffer->buffer == NULL) {
316 fprintf(stderr, "vnc: out of memory\n");
317 exit(1);
318 }
aliguori89064282009-02-02 15:58:47 +0000319 }
320}
321
aliguori2f9606b2009-03-06 20:27:28 +0000322int buffer_empty(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000323{
324 return buffer->offset == 0;
325}
326
aliguori2f9606b2009-03-06 20:27:28 +0000327uint8_t *buffer_end(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000328{
329 return buffer->buffer + buffer->offset;
330}
331
aliguori2f9606b2009-03-06 20:27:28 +0000332void buffer_reset(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000333{
aliguori28a76be2009-03-06 20:27:40 +0000334 buffer->offset = 0;
aliguori89064282009-02-02 15:58:47 +0000335}
336
aliguori2f9606b2009-03-06 20:27:28 +0000337void buffer_append(Buffer *buffer, const void *data, size_t len)
aliguori89064282009-02-02 15:58:47 +0000338{
339 memcpy(buffer->buffer + buffer->offset, data, len);
340 buffer->offset += len;
341}
342
aliguori753b4052009-02-16 14:59:30 +0000343static void vnc_dpy_resize(DisplayState *ds)
344{
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100345 int size_changed;
aliguori753b4052009-02-16 14:59:30 +0000346 VncDisplay *vd = ds->opaque;
347 VncState *vs = vd->clients;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100348
349 /* server surface */
350 if (!vd->server)
351 vd->server = qemu_mallocz(sizeof(*vd->server));
352 if (vd->server->data)
353 qemu_free(vd->server->data);
354 *(vd->server) = *(ds->surface);
355 vd->server->data = qemu_mallocz(vd->server->linesize *
356 vd->server->height);
357
358 /* guest surface */
359 if (!vd->guest.ds)
360 vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
361 if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
362 console_color_init(ds);
363 size_changed = ds_get_width(ds) != vd->guest.ds->width ||
364 ds_get_height(ds) != vd->guest.ds->height;
365 *(vd->guest.ds) = *(ds->surface);
366 memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
367
aliguori753b4052009-02-16 14:59:30 +0000368 while (vs != NULL) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100369 vnc_colordepth(vs);
370 if (size_changed) {
371 if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
372 vnc_write_u8(vs, 0); /* msg id */
373 vnc_write_u8(vs, 0);
374 vnc_write_u16(vs, 1); /* number of rects */
375 vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
376 VNC_ENCODING_DESKTOPRESIZE);
377 vnc_flush(vs);
378 }
379 }
380 memset(vs->dirty, 0xFF, sizeof(vs->dirty));
aliguori753b4052009-02-16 14:59:30 +0000381 vs = vs->next;
382 }
383}
384
bellard35127792006-05-14 18:11:49 +0000385/* fastest code */
386static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
387{
388 vnc_write(vs, pixels, size);
389}
390
391/* slowest but generic code. */
392static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
393{
aliguori7eac3a82008-09-15 16:03:41 +0000394 uint8_t r, g, b;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100395 VncDisplay *vd = vs->vd;
bellard35127792006-05-14 18:11:49 +0000396
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100397 r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >>
398 vd->server->pf.rbits);
399 g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >>
400 vd->server->pf.gbits);
401 b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >>
402 vd->server->pf.bbits);
aliguori6cec5482009-01-15 22:17:38 +0000403 v = (r << vs->clientds.pf.rshift) |
404 (g << vs->clientds.pf.gshift) |
405 (b << vs->clientds.pf.bshift);
406 switch(vs->clientds.pf.bytes_per_pixel) {
bellard35127792006-05-14 18:11:49 +0000407 case 1:
408 buf[0] = v;
409 break;
410 case 2:
aliguori6cec5482009-01-15 22:17:38 +0000411 if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
bellard35127792006-05-14 18:11:49 +0000412 buf[0] = v >> 8;
413 buf[1] = v;
414 } else {
415 buf[1] = v >> 8;
416 buf[0] = v;
417 }
418 break;
419 default:
420 case 4:
aliguori6cec5482009-01-15 22:17:38 +0000421 if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
bellard35127792006-05-14 18:11:49 +0000422 buf[0] = v >> 24;
423 buf[1] = v >> 16;
424 buf[2] = v >> 8;
425 buf[3] = v;
426 } else {
427 buf[3] = v >> 24;
428 buf[2] = v >> 16;
429 buf[1] = v >> 8;
430 buf[0] = v;
431 }
432 break;
433 }
434}
435
436static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
437{
bellard35127792006-05-14 18:11:49 +0000438 uint8_t buf[4];
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100439 VncDisplay *vd = vs->vd;
bellard35127792006-05-14 18:11:49 +0000440
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100441 if (vd->server->pf.bytes_per_pixel == 4) {
aliguori7eac3a82008-09-15 16:03:41 +0000442 uint32_t *pixels = pixels1;
443 int n, i;
444 n = size >> 2;
445 for(i = 0; i < n; i++) {
446 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000447 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000448 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100449 } else if (vd->server->pf.bytes_per_pixel == 2) {
aliguori7eac3a82008-09-15 16:03:41 +0000450 uint16_t *pixels = pixels1;
451 int n, i;
452 n = size >> 1;
453 for(i = 0; i < n; i++) {
454 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000455 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000456 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100457 } else if (vd->server->pf.bytes_per_pixel == 1) {
aliguori7eac3a82008-09-15 16:03:41 +0000458 uint8_t *pixels = pixels1;
459 int n, i;
460 n = size;
461 for(i = 0; i < n; i++) {
462 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000463 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000464 }
465 } else {
466 fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
bellard35127792006-05-14 18:11:49 +0000467 }
468}
469
bellard24236862006-04-30 21:28:36 +0000470static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
471{
472 int i;
ths60fe76f2007-12-16 03:02:09 +0000473 uint8_t *row;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100474 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000475
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100476 row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
bellard24236862006-04-30 21:28:36 +0000477 for (i = 0; i < h; i++) {
aliguori28a76be2009-03-06 20:27:40 +0000478 vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
479 row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +0000480 }
481}
482
483static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
484{
485 ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
486 ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
487}
488
489#define BPP 8
490#include "vnchextile.h"
491#undef BPP
492
493#define BPP 16
494#include "vnchextile.h"
495#undef BPP
496
497#define BPP 32
498#include "vnchextile.h"
499#undef BPP
500
bellard35127792006-05-14 18:11:49 +0000501#define GENERIC
aliguori7eac3a82008-09-15 16:03:41 +0000502#define BPP 8
503#include "vnchextile.h"
504#undef BPP
505#undef GENERIC
506
507#define GENERIC
508#define BPP 16
509#include "vnchextile.h"
510#undef BPP
511#undef GENERIC
512
513#define GENERIC
bellard35127792006-05-14 18:11:49 +0000514#define BPP 32
515#include "vnchextile.h"
516#undef BPP
517#undef GENERIC
518
bellard24236862006-04-30 21:28:36 +0000519static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
520{
521 int i, j;
522 int has_fg, has_bg;
aliguori7eac3a82008-09-15 16:03:41 +0000523 uint8_t *last_fg, *last_bg;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100524 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000525
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100526 last_fg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
527 last_bg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
bellard24236862006-04-30 21:28:36 +0000528 has_fg = has_bg = 0;
529 for (j = y; j < (y + h); j += 16) {
aliguori28a76be2009-03-06 20:27:40 +0000530 for (i = x; i < (x + w); i += 16) {
ths5fafdf22007-09-16 21:08:06 +0000531 vs->send_hextile_tile(vs, i, j,
bellard35127792006-05-14 18:11:49 +0000532 MIN(16, x + w - i), MIN(16, y + h - j),
aliguori7eac3a82008-09-15 16:03:41 +0000533 last_bg, last_fg, &has_bg, &has_fg);
aliguori28a76be2009-03-06 20:27:40 +0000534 }
bellard24236862006-04-30 21:28:36 +0000535 }
aliguori7eac3a82008-09-15 16:03:41 +0000536 free(last_fg);
537 free(last_bg);
538
bellard24236862006-04-30 21:28:36 +0000539}
540
Stefan Weil6c098402009-10-01 20:53:12 +0200541#define ZALLOC_ALIGNMENT 16
542
543static void *zalloc(void *x, unsigned items, unsigned size)
544{
545 void *p;
546
547 size *= items;
548 size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
549
550 p = qemu_mallocz(size);
551
552 return (p);
553}
554
555static void zfree(void *x, void *addr)
556{
557 qemu_free(addr);
558}
559
aliguori059cef42009-02-02 15:58:54 +0000560static void vnc_zlib_init(VncState *vs)
561{
562 int i;
563 for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++)
564 vs->zlib_stream[i].opaque = NULL;
565}
566
567static void vnc_zlib_start(VncState *vs)
568{
569 buffer_reset(&vs->zlib);
570
571 // make the output buffer be the zlib buffer, so we can compress it later
572 vs->zlib_tmp = vs->output;
573 vs->output = vs->zlib;
574}
575
576static int vnc_zlib_stop(VncState *vs, int stream_id)
577{
578 z_streamp zstream = &vs->zlib_stream[stream_id];
579 int previous_out;
580
581 // switch back to normal output/zlib buffers
582 vs->zlib = vs->output;
583 vs->output = vs->zlib_tmp;
584
585 // compress the zlib buffer
586
587 // initialize the stream
588 // XXX need one stream per session
589 if (zstream->opaque != vs) {
590 int err;
591
592 VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
593 VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
Stefan Weil6c098402009-10-01 20:53:12 +0200594 zstream->zalloc = zalloc;
595 zstream->zfree = zfree;
aliguori059cef42009-02-02 15:58:54 +0000596
597 err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
598 MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
599
600 if (err != Z_OK) {
601 fprintf(stderr, "VNC: error initializing zlib\n");
602 return -1;
603 }
604
605 zstream->opaque = vs;
606 }
607
608 // XXX what to do if tight_compression changed in between?
609
610 // reserve memory in output buffer
611 buffer_reserve(&vs->output, vs->zlib.offset + 64);
612
613 // set pointers
614 zstream->next_in = vs->zlib.buffer;
615 zstream->avail_in = vs->zlib.offset;
616 zstream->next_out = vs->output.buffer + vs->output.offset;
617 zstream->avail_out = vs->output.capacity - vs->output.offset;
618 zstream->data_type = Z_BINARY;
619 previous_out = zstream->total_out;
620
621 // start encoding
622 if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
623 fprintf(stderr, "VNC: error during zlib compression\n");
624 return -1;
625 }
626
627 vs->output.offset = vs->output.capacity - zstream->avail_out;
628 return zstream->total_out - previous_out;
629}
630
631static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h)
632{
633 int old_offset, new_offset, bytes_written;
634
635 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
636
637 // remember where we put in the follow-up size
638 old_offset = vs->output.offset;
639 vnc_write_s32(vs, 0);
640
641 // compress the stream
642 vnc_zlib_start(vs);
643 send_framebuffer_update_raw(vs, x, y, w, h);
644 bytes_written = vnc_zlib_stop(vs, 0);
645
646 if (bytes_written == -1)
647 return;
648
649 // hack in the size
650 new_offset = vs->output.offset;
651 vs->output.offset = old_offset;
652 vnc_write_u32(vs, bytes_written);
653 vs->output.offset = new_offset;
654}
655
bellard24236862006-04-30 21:28:36 +0000656static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
657{
aliguorifb437312009-02-02 15:58:43 +0000658 switch(vs->vnc_encoding) {
aliguori28a76be2009-03-06 20:27:40 +0000659 case VNC_ENCODING_ZLIB:
660 send_framebuffer_update_zlib(vs, x, y, w, h);
661 break;
662 case VNC_ENCODING_HEXTILE:
663 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
664 send_framebuffer_update_hextile(vs, x, y, w, h);
665 break;
666 default:
667 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
668 send_framebuffer_update_raw(vs, x, y, w, h);
669 break;
aliguorifb437312009-02-02 15:58:43 +0000670 }
bellard24236862006-04-30 21:28:36 +0000671}
672
aliguori753b4052009-02-16 14:59:30 +0000673static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000674{
Gerd Hoffmann3e28c9a2009-07-27 17:10:48 +0200675 /* send bitblit op to the vnc client */
bellard24236862006-04-30 21:28:36 +0000676 vnc_write_u8(vs, 0); /* msg id */
677 vnc_write_u8(vs, 0);
678 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000679 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
bellard24236862006-04-30 21:28:36 +0000680 vnc_write_u16(vs, src_x);
681 vnc_write_u16(vs, src_y);
682 vnc_flush(vs);
683}
684
aliguori753b4052009-02-16 14:59:30 +0000685static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
686{
687 VncDisplay *vd = ds->opaque;
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200688 VncState *vs, *vn;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100689 uint8_t *src_row;
690 uint8_t *dst_row;
691 int i,x,y,pitch,depth,inc,w_lim,s;
692 int cmp_bytes;
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200693
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100694 vnc_refresh_server_surface(vd);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200695 for (vs = vd->clients; vs != NULL; vs = vn) {
696 vn = vs->next;
697 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
698 vs->force_update = 1;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100699 vnc_update_client(vs, 1);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200700 /* vs might be free()ed here */
701 }
702 }
703
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100704 /* do bitblit op on the local surface too */
705 pitch = ds_get_linesize(vd->ds);
706 depth = ds_get_bytes_per_pixel(vd->ds);
707 src_row = vd->server->data + pitch * src_y + depth * src_x;
708 dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
709 y = dst_y;
710 inc = 1;
711 if (dst_y > src_y) {
712 /* copy backwards */
713 src_row += pitch * (h-1);
714 dst_row += pitch * (h-1);
715 pitch = -pitch;
716 y = dst_y + h - 1;
717 inc = -1;
718 }
719 w_lim = w - (16 - (dst_x % 16));
720 if (w_lim < 0)
721 w_lim = w;
722 else
723 w_lim = w - (w_lim % 16);
724 for (i = 0; i < h; i++) {
725 for (x = 0; x <= w_lim;
726 x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
727 if (x == w_lim) {
728 if ((s = w - w_lim) == 0)
729 break;
730 } else if (!x) {
731 s = (16 - (dst_x % 16));
732 s = MIN(s, w_lim);
733 } else {
734 s = 16;
735 }
736 cmp_bytes = s * depth;
737 if (memcmp(src_row, dst_row, cmp_bytes) == 0)
738 continue;
739 memmove(dst_row, src_row, cmp_bytes);
740 vs = vd->clients;
741 while (vs != NULL) {
742 if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
743 vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16));
744 vs = vs->next;
745 }
746 }
747 src_row += pitch - w * depth;
748 dst_row += pitch - w * depth;
749 y += inc;
750 }
751
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200752 for (vs = vd->clients; vs != NULL; vs = vs->next) {
aliguori753b4052009-02-16 14:59:30 +0000753 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
754 vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
aliguori753b4052009-02-16 14:59:30 +0000755 }
756}
757
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100758static int find_and_clear_dirty_height(struct VncState *vs,
aliguori6baebed2009-03-20 15:59:14 +0000759 int y, int last_x, int x)
bellard24236862006-04-30 21:28:36 +0000760{
761 int h;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100762 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000763
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100764 for (h = 1; h < (vd->server->height - y); h++) {
aliguori28a76be2009-03-06 20:27:40 +0000765 int tmp_x;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100766 if (!vnc_get_bit(vs->dirty[y + h], last_x))
aliguori28a76be2009-03-06 20:27:40 +0000767 break;
768 for (tmp_x = last_x; tmp_x < x; tmp_x++)
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100769 vnc_clear_bit(vs->dirty[y + h], tmp_x);
bellard24236862006-04-30 21:28:36 +0000770 }
771
772 return h;
773}
774
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100775static int vnc_update_client(VncState *vs, int has_dirty)
bellard24236862006-04-30 21:28:36 +0000776{
bellard24236862006-04-30 21:28:36 +0000777 if (vs->need_update && vs->csock != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100778 VncDisplay *vd = vs->vd;
aliguori28a76be2009-03-06 20:27:40 +0000779 int y;
aliguori28a76be2009-03-06 20:27:40 +0000780 int n_rectangles;
781 int saved_offset;
bellard24236862006-04-30 21:28:36 +0000782
Stefano Stabellini703bc682009-08-03 10:54:05 +0100783 if (vs->output.offset && !vs->audio_cap && !vs->force_update)
aliguoric522d0e2009-03-20 15:59:24 +0000784 /* kernel send buffers are full -> drop frames to throttle */
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100785 return 0;
balroga0ecfb72008-01-13 23:51:53 +0000786
Stefano Stabellini703bc682009-08-03 10:54:05 +0100787 if (!has_dirty && !vs->audio_cap && !vs->force_update)
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100788 return 0;
bellard24236862006-04-30 21:28:36 +0000789
aliguori6baebed2009-03-20 15:59:14 +0000790 /*
791 * Send screen updates to the vnc client using the server
792 * surface and server dirty map. guest surface updates
793 * happening in parallel don't disturb us, the next pass will
794 * send them to the client.
795 */
aliguori28a76be2009-03-06 20:27:40 +0000796 n_rectangles = 0;
797 vnc_write_u8(vs, 0); /* msg id */
798 vnc_write_u8(vs, 0);
799 saved_offset = vs->output.offset;
800 vnc_write_u16(vs, 0);
bellard24236862006-04-30 21:28:36 +0000801
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100802 for (y = 0; y < vd->server->height; y++) {
aliguori28a76be2009-03-06 20:27:40 +0000803 int x;
804 int last_x = -1;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100805 for (x = 0; x < vd->server->width / 16; x++) {
806 if (vnc_get_bit(vs->dirty[y], x)) {
aliguori28a76be2009-03-06 20:27:40 +0000807 if (last_x == -1) {
808 last_x = x;
809 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100810 vnc_clear_bit(vs->dirty[y], x);
aliguori28a76be2009-03-06 20:27:40 +0000811 } else {
812 if (last_x != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100813 int h = find_and_clear_dirty_height(vs, y, last_x, x);
aliguori28a76be2009-03-06 20:27:40 +0000814 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
815 n_rectangles++;
816 }
817 last_x = -1;
818 }
819 }
820 if (last_x != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100821 int h = find_and_clear_dirty_height(vs, y, last_x, x);
aliguori28a76be2009-03-06 20:27:40 +0000822 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
823 n_rectangles++;
824 }
825 }
826 vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
827 vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
828 vnc_flush(vs);
aliguoric522d0e2009-03-20 15:59:24 +0000829 vs->force_update = 0;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100830 return n_rectangles;
bellard24236862006-04-30 21:28:36 +0000831 }
bellard24236862006-04-30 21:28:36 +0000832
Stefano Stabellini703bc682009-08-03 10:54:05 +0100833 if (vs->csock == -1)
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200834 vnc_disconnect_finish(vs);
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100835
836 return 0;
bellard24236862006-04-30 21:28:36 +0000837}
838
malc429a8ed2008-12-01 20:57:48 +0000839/* audio */
840static void audio_capture_notify(void *opaque, audcnotification_e cmd)
841{
842 VncState *vs = opaque;
843
844 switch (cmd) {
845 case AUD_CNOTIFY_DISABLE:
846 vnc_write_u8(vs, 255);
847 vnc_write_u8(vs, 1);
848 vnc_write_u16(vs, 0);
849 vnc_flush(vs);
850 break;
851
852 case AUD_CNOTIFY_ENABLE:
853 vnc_write_u8(vs, 255);
854 vnc_write_u8(vs, 1);
855 vnc_write_u16(vs, 1);
856 vnc_flush(vs);
857 break;
858 }
859}
860
861static void audio_capture_destroy(void *opaque)
862{
863}
864
865static void audio_capture(void *opaque, void *buf, int size)
866{
867 VncState *vs = opaque;
868
869 vnc_write_u8(vs, 255);
870 vnc_write_u8(vs, 1);
871 vnc_write_u16(vs, 2);
872 vnc_write_u32(vs, size);
873 vnc_write(vs, buf, size);
874 vnc_flush(vs);
875}
876
877static void audio_add(VncState *vs)
878{
aliguori376253e2009-03-05 23:01:23 +0000879 Monitor *mon = cur_mon;
malc429a8ed2008-12-01 20:57:48 +0000880 struct audio_capture_ops ops;
881
882 if (vs->audio_cap) {
aliguori376253e2009-03-05 23:01:23 +0000883 monitor_printf(mon, "audio already running\n");
malc429a8ed2008-12-01 20:57:48 +0000884 return;
885 }
886
887 ops.notify = audio_capture_notify;
888 ops.destroy = audio_capture_destroy;
889 ops.capture = audio_capture;
890
malc1a7dafc2009-05-14 03:11:35 +0400891 vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
malc429a8ed2008-12-01 20:57:48 +0000892 if (!vs->audio_cap) {
aliguori376253e2009-03-05 23:01:23 +0000893 monitor_printf(mon, "Failed to add audio capture\n");
malc429a8ed2008-12-01 20:57:48 +0000894 }
895}
896
897static void audio_del(VncState *vs)
898{
899 if (vs->audio_cap) {
900 AUD_del_capture(vs->audio_cap, vs);
901 vs->audio_cap = NULL;
902 }
903}
904
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200905static void vnc_disconnect_start(VncState *vs)
906{
907 if (vs->csock == -1)
908 return;
909 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
910 closesocket(vs->csock);
911 vs->csock = -1;
912}
913
914static void vnc_disconnect_finish(VncState *vs)
915{
Stefan Weilfa0cfdf2009-09-19 21:00:09 +0200916 if (vs->input.buffer) {
917 qemu_free(vs->input.buffer);
918 vs->input.buffer = NULL;
919 }
920 if (vs->output.buffer) {
921 qemu_free(vs->output.buffer);
922 vs->output.buffer = NULL;
923 }
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200924#ifdef CONFIG_VNC_TLS
925 vnc_tls_client_cleanup(vs);
926#endif /* CONFIG_VNC_TLS */
927#ifdef CONFIG_VNC_SASL
928 vnc_sasl_client_cleanup(vs);
929#endif /* CONFIG_VNC_SASL */
930 audio_del(vs);
931
932 VncState *p, *parent = NULL;
933 for (p = vs->vd->clients; p != NULL; p = p->next) {
934 if (p == vs) {
935 if (parent)
936 parent->next = p->next;
937 else
938 vs->vd->clients = p->next;
939 break;
940 }
941 parent = p;
942 }
943 if (!vs->vd->clients)
944 dcl->idle = 1;
945
Stefano Stabellini703bc682009-08-03 10:54:05 +0100946 vnc_remove_timer(vs->vd);
Glauber Costa5d95ac52009-09-25 08:30:57 -0400947 qemu_free(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200948}
aliguori2f9606b2009-03-06 20:27:28 +0000949
950int vnc_client_io_error(VncState *vs, int ret, int last_errno)
bellard24236862006-04-30 21:28:36 +0000951{
952 if (ret == 0 || ret == -1) {
balrogea01e5f2008-04-24 23:40:55 +0000953 if (ret == -1) {
954 switch (last_errno) {
955 case EINTR:
956 case EAGAIN:
957#ifdef _WIN32
958 case WSAEWOULDBLOCK:
959#endif
960 return 0;
961 default:
962 break;
963 }
964 }
bellard24236862006-04-30 21:28:36 +0000965
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200966 VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
967 ret, ret < 0 ? last_errno : 0);
968 vnc_disconnect_start(vs);
aliguori6baebed2009-03-20 15:59:14 +0000969
aliguori28a76be2009-03-06 20:27:40 +0000970 return 0;
bellard24236862006-04-30 21:28:36 +0000971 }
972 return ret;
973}
974
aliguori5fb6c7a2009-03-06 20:27:23 +0000975
976void vnc_client_error(VncState *vs)
bellard24236862006-04-30 21:28:36 +0000977{
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200978 VNC_DEBUG("Closing down client sock: protocol error\n");
979 vnc_disconnect_start(vs);
bellard24236862006-04-30 21:28:36 +0000980}
981
aliguori2f9606b2009-03-06 20:27:28 +0000982
983/*
984 * Called to write a chunk of data to the client socket. The data may
985 * be the raw data, or may have already been encoded by SASL.
986 * The data will be written either straight onto the socket, or
987 * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
988 *
989 * NB, it is theoretically possible to have 2 layers of encryption,
990 * both SASL, and this TLS layer. It is highly unlikely in practice
991 * though, since SASL encryption will typically be a no-op if TLS
992 * is active
993 *
994 * Returns the number of bytes written, which may be less than
995 * the requested 'datalen' if the socket would block. Returns
996 * -1 on error, and disconnects the client socket.
997 */
998long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +0000999{
bellardceb5caa2006-05-03 21:18:59 +00001000 long ret;
blueswir1eb38c522008-09-06 17:47:39 +00001001#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +00001002 if (vs->tls.session) {
aliguori28a76be2009-03-06 20:27:40 +00001003 ret = gnutls_write(vs->tls.session, data, datalen);
1004 if (ret < 0) {
1005 if (ret == GNUTLS_E_AGAIN)
1006 errno = EAGAIN;
1007 else
1008 errno = EIO;
1009 ret = -1;
1010 }
ths8d5d2d42007-08-25 01:37:51 +00001011 } else
1012#endif /* CONFIG_VNC_TLS */
Stefan Weil70503262009-06-13 13:05:27 +02001013 ret = send(vs->csock, (const void *)data, datalen, 0);
aliguori23decc82009-03-20 15:59:18 +00001014 VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +00001015 return vnc_client_io_error(vs, ret, socket_error());
1016}
1017
1018
1019/*
1020 * Called to write buffered data to the client socket, when not
1021 * using any SASL SSF encryption layers. Will write as much data
1022 * as possible without blocking. If all buffered data is written,
1023 * will switch the FD poll() handler back to read monitoring.
1024 *
1025 * Returns the number of bytes written, which may be less than
1026 * the buffered output data if the socket would block. Returns
1027 * -1 on error, and disconnects the client socket.
1028 */
1029static long vnc_client_write_plain(VncState *vs)
1030{
1031 long ret;
1032
1033#ifdef CONFIG_VNC_SASL
aliguori23decc82009-03-20 15:59:18 +00001034 VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
aliguori2f9606b2009-03-06 20:27:28 +00001035 vs->output.buffer, vs->output.capacity, vs->output.offset,
1036 vs->sasl.waitWriteSSF);
1037
1038 if (vs->sasl.conn &&
1039 vs->sasl.runSSF &&
1040 vs->sasl.waitWriteSSF) {
1041 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
1042 if (ret)
1043 vs->sasl.waitWriteSSF -= ret;
1044 } else
1045#endif /* CONFIG_VNC_SASL */
1046 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
bellard24236862006-04-30 21:28:36 +00001047 if (!ret)
aliguori2f9606b2009-03-06 20:27:28 +00001048 return 0;
bellard24236862006-04-30 21:28:36 +00001049
1050 memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
1051 vs->output.offset -= ret;
1052
1053 if (vs->output.offset == 0) {
aliguori28a76be2009-03-06 20:27:40 +00001054 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00001055 }
aliguori2f9606b2009-03-06 20:27:28 +00001056
1057 return ret;
1058}
1059
1060
1061/*
1062 * First function called whenever there is data to be written to
1063 * the client socket. Will delegate actual work according to whether
1064 * SASL SSF layers are enabled (thus requiring encryption calls)
1065 */
1066void vnc_client_write(void *opaque)
1067{
1068 long ret;
1069 VncState *vs = opaque;
1070
1071#ifdef CONFIG_VNC_SASL
1072 if (vs->sasl.conn &&
1073 vs->sasl.runSSF &&
1074 !vs->sasl.waitWriteSSF)
1075 ret = vnc_client_write_sasl(vs);
1076 else
1077#endif /* CONFIG_VNC_SASL */
1078 ret = vnc_client_write_plain(vs);
bellard24236862006-04-30 21:28:36 +00001079}
1080
aliguori5fb6c7a2009-03-06 20:27:23 +00001081void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
bellard24236862006-04-30 21:28:36 +00001082{
1083 vs->read_handler = func;
1084 vs->read_handler_expect = expecting;
1085}
1086
aliguori2f9606b2009-03-06 20:27:28 +00001087
1088/*
1089 * Called to read a chunk of data from the client socket. The data may
1090 * be the raw data, or may need to be further decoded by SASL.
1091 * The data will be read either straight from to the socket, or
1092 * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1093 *
1094 * NB, it is theoretically possible to have 2 layers of encryption,
1095 * both SASL, and this TLS layer. It is highly unlikely in practice
1096 * though, since SASL encryption will typically be a no-op if TLS
1097 * is active
1098 *
1099 * Returns the number of bytes read, which may be less than
1100 * the requested 'datalen' if the socket would block. Returns
1101 * -1 on error, and disconnects the client socket.
1102 */
1103long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001104{
bellardceb5caa2006-05-03 21:18:59 +00001105 long ret;
blueswir1eb38c522008-09-06 17:47:39 +00001106#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +00001107 if (vs->tls.session) {
aliguori28a76be2009-03-06 20:27:40 +00001108 ret = gnutls_read(vs->tls.session, data, datalen);
1109 if (ret < 0) {
1110 if (ret == GNUTLS_E_AGAIN)
1111 errno = EAGAIN;
1112 else
1113 errno = EIO;
1114 ret = -1;
1115 }
ths8d5d2d42007-08-25 01:37:51 +00001116 } else
1117#endif /* CONFIG_VNC_TLS */
Blue Swirlc5b76b32009-06-13 08:44:31 +00001118 ret = recv(vs->csock, (void *)data, datalen, 0);
aliguori23decc82009-03-20 15:59:18 +00001119 VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +00001120 return vnc_client_io_error(vs, ret, socket_error());
1121}
1122
1123
1124/*
1125 * Called to read data from the client socket to the input buffer,
1126 * when not using any SASL SSF encryption layers. Will read as much
1127 * data as possible without blocking.
1128 *
1129 * Returns the number of bytes read. Returns -1 on error, and
1130 * disconnects the client socket.
1131 */
1132static long vnc_client_read_plain(VncState *vs)
1133{
1134 int ret;
aliguori23decc82009-03-20 15:59:18 +00001135 VNC_DEBUG("Read plain %p size %zd offset %zd\n",
aliguori2f9606b2009-03-06 20:27:28 +00001136 vs->input.buffer, vs->input.capacity, vs->input.offset);
1137 buffer_reserve(&vs->input, 4096);
1138 ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
1139 if (!ret)
1140 return 0;
1141 vs->input.offset += ret;
1142 return ret;
1143}
1144
1145
1146/*
1147 * First function called whenever there is more data to be read from
1148 * the client socket. Will delegate actual work according to whether
1149 * SASL SSF layers are enabled (thus requiring decryption calls)
1150 */
1151void vnc_client_read(void *opaque)
1152{
1153 VncState *vs = opaque;
1154 long ret;
1155
1156#ifdef CONFIG_VNC_SASL
1157 if (vs->sasl.conn && vs->sasl.runSSF)
1158 ret = vnc_client_read_sasl(vs);
1159 else
1160#endif /* CONFIG_VNC_SASL */
1161 ret = vnc_client_read_plain(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001162 if (!ret) {
1163 if (vs->csock == -1)
1164 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001165 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001166 }
bellard24236862006-04-30 21:28:36 +00001167
bellard24236862006-04-30 21:28:36 +00001168 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
aliguori28a76be2009-03-06 20:27:40 +00001169 size_t len = vs->read_handler_expect;
1170 int ret;
bellard24236862006-04-30 21:28:36 +00001171
aliguori28a76be2009-03-06 20:27:40 +00001172 ret = vs->read_handler(vs, vs->input.buffer, len);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001173 if (vs->csock == -1) {
1174 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001175 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001176 }
bellard24236862006-04-30 21:28:36 +00001177
aliguori28a76be2009-03-06 20:27:40 +00001178 if (!ret) {
1179 memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
1180 vs->input.offset -= len;
1181 } else {
1182 vs->read_handler_expect = ret;
1183 }
bellard24236862006-04-30 21:28:36 +00001184 }
1185}
1186
aliguori5fb6c7a2009-03-06 20:27:23 +00001187void vnc_write(VncState *vs, const void *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001188{
1189 buffer_reserve(&vs->output, len);
1190
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001191 if (vs->csock != -1 && buffer_empty(&vs->output)) {
aliguori28a76be2009-03-06 20:27:40 +00001192 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
bellard24236862006-04-30 21:28:36 +00001193 }
1194
1195 buffer_append(&vs->output, data, len);
1196}
1197
aliguori5fb6c7a2009-03-06 20:27:23 +00001198void vnc_write_s32(VncState *vs, int32_t value)
bellard24236862006-04-30 21:28:36 +00001199{
1200 vnc_write_u32(vs, *(uint32_t *)&value);
1201}
1202
aliguori5fb6c7a2009-03-06 20:27:23 +00001203void vnc_write_u32(VncState *vs, uint32_t value)
bellard24236862006-04-30 21:28:36 +00001204{
1205 uint8_t buf[4];
1206
1207 buf[0] = (value >> 24) & 0xFF;
1208 buf[1] = (value >> 16) & 0xFF;
1209 buf[2] = (value >> 8) & 0xFF;
1210 buf[3] = value & 0xFF;
1211
1212 vnc_write(vs, buf, 4);
1213}
1214
aliguori5fb6c7a2009-03-06 20:27:23 +00001215void vnc_write_u16(VncState *vs, uint16_t value)
bellard24236862006-04-30 21:28:36 +00001216{
bellard64f5a132006-08-24 20:36:44 +00001217 uint8_t buf[2];
bellard24236862006-04-30 21:28:36 +00001218
1219 buf[0] = (value >> 8) & 0xFF;
1220 buf[1] = value & 0xFF;
1221
1222 vnc_write(vs, buf, 2);
1223}
1224
aliguori5fb6c7a2009-03-06 20:27:23 +00001225void vnc_write_u8(VncState *vs, uint8_t value)
bellard24236862006-04-30 21:28:36 +00001226{
1227 vnc_write(vs, (char *)&value, 1);
1228}
1229
aliguori5fb6c7a2009-03-06 20:27:23 +00001230void vnc_flush(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001231{
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001232 if (vs->csock != -1 && vs->output.offset)
aliguori28a76be2009-03-06 20:27:40 +00001233 vnc_client_write(vs);
bellard24236862006-04-30 21:28:36 +00001234}
1235
aliguori5fb6c7a2009-03-06 20:27:23 +00001236uint8_t read_u8(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001237{
1238 return data[offset];
1239}
1240
aliguori5fb6c7a2009-03-06 20:27:23 +00001241uint16_t read_u16(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001242{
1243 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
1244}
1245
aliguori5fb6c7a2009-03-06 20:27:23 +00001246int32_t read_s32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001247{
1248 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001249 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001250}
1251
aliguori5fb6c7a2009-03-06 20:27:23 +00001252uint32_t read_u32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001253{
1254 return ((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001255 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001256}
1257
ths60fe76f2007-12-16 03:02:09 +00001258static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
bellard24236862006-04-30 21:28:36 +00001259{
1260}
1261
bellard564c3372007-02-05 20:14:10 +00001262static void check_pointer_type_change(VncState *vs, int absolute)
1263{
aliguori29fa4ed2009-02-02 15:58:29 +00001264 if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
aliguori28a76be2009-03-06 20:27:40 +00001265 vnc_write_u8(vs, 0);
1266 vnc_write_u8(vs, 0);
1267 vnc_write_u16(vs, 1);
1268 vnc_framebuffer_update(vs, absolute, 0,
1269 ds_get_width(vs->ds), ds_get_height(vs->ds),
aliguori29fa4ed2009-02-02 15:58:29 +00001270 VNC_ENCODING_POINTER_TYPE_CHANGE);
aliguori28a76be2009-03-06 20:27:40 +00001271 vnc_flush(vs);
bellard564c3372007-02-05 20:14:10 +00001272 }
1273 vs->absolute = absolute;
1274}
1275
bellard24236862006-04-30 21:28:36 +00001276static void pointer_event(VncState *vs, int button_mask, int x, int y)
1277{
1278 int buttons = 0;
1279 int dz = 0;
1280
1281 if (button_mask & 0x01)
aliguori28a76be2009-03-06 20:27:40 +00001282 buttons |= MOUSE_EVENT_LBUTTON;
bellard24236862006-04-30 21:28:36 +00001283 if (button_mask & 0x02)
aliguori28a76be2009-03-06 20:27:40 +00001284 buttons |= MOUSE_EVENT_MBUTTON;
bellard24236862006-04-30 21:28:36 +00001285 if (button_mask & 0x04)
aliguori28a76be2009-03-06 20:27:40 +00001286 buttons |= MOUSE_EVENT_RBUTTON;
bellard24236862006-04-30 21:28:36 +00001287 if (button_mask & 0x08)
aliguori28a76be2009-03-06 20:27:40 +00001288 dz = -1;
bellard24236862006-04-30 21:28:36 +00001289 if (button_mask & 0x10)
aliguori28a76be2009-03-06 20:27:40 +00001290 dz = 1;
bellard564c3372007-02-05 20:14:10 +00001291
1292 if (vs->absolute) {
aliguori28a76be2009-03-06 20:27:40 +00001293 kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
1294 y * 0x7FFF / (ds_get_height(vs->ds) - 1),
1295 dz, buttons);
aliguori29fa4ed2009-02-02 15:58:29 +00001296 } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
aliguori28a76be2009-03-06 20:27:40 +00001297 x -= 0x7FFF;
1298 y -= 0x7FFF;
bellard564c3372007-02-05 20:14:10 +00001299
aliguori28a76be2009-03-06 20:27:40 +00001300 kbd_mouse_event(x, y, dz, buttons);
bellard24236862006-04-30 21:28:36 +00001301 } else {
aliguori28a76be2009-03-06 20:27:40 +00001302 if (vs->last_x != -1)
1303 kbd_mouse_event(x - vs->last_x,
1304 y - vs->last_y,
1305 dz, buttons);
1306 vs->last_x = x;
1307 vs->last_y = y;
bellard24236862006-04-30 21:28:36 +00001308 }
bellard564c3372007-02-05 20:14:10 +00001309
1310 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001311}
1312
bellard64f5a132006-08-24 20:36:44 +00001313static void reset_keys(VncState *vs)
1314{
1315 int i;
1316 for(i = 0; i < 256; i++) {
1317 if (vs->modifiers_state[i]) {
1318 if (i & 0x80)
1319 kbd_put_keycode(0xe0);
1320 kbd_put_keycode(i | 0x80);
1321 vs->modifiers_state[i] = 0;
1322 }
1323 }
1324}
1325
balroga528b802007-10-30 22:38:53 +00001326static void press_key(VncState *vs, int keysym)
1327{
aliguori753b4052009-02-16 14:59:30 +00001328 kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f);
1329 kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80);
balroga528b802007-10-30 22:38:53 +00001330}
1331
aliguori9ca313a2008-08-23 23:27:37 +00001332static void do_key_event(VncState *vs, int down, int keycode, int sym)
bellard24236862006-04-30 21:28:36 +00001333{
bellard64f5a132006-08-24 20:36:44 +00001334 /* QEMU console switch */
1335 switch(keycode) {
1336 case 0x2a: /* Left Shift */
1337 case 0x36: /* Right Shift */
1338 case 0x1d: /* Left CTRL */
1339 case 0x9d: /* Right CTRL */
1340 case 0x38: /* Left ALT */
1341 case 0xb8: /* Right ALT */
1342 if (down)
1343 vs->modifiers_state[keycode] = 1;
1344 else
1345 vs->modifiers_state[keycode] = 0;
1346 break;
ths5fafdf22007-09-16 21:08:06 +00001347 case 0x02 ... 0x0a: /* '1' to '9' keys */
bellard64f5a132006-08-24 20:36:44 +00001348 if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1349 /* Reset the modifiers sent to the current console */
1350 reset_keys(vs);
1351 console_select(keycode - 0x02);
1352 return;
1353 }
1354 break;
aliguori28a76be2009-03-06 20:27:40 +00001355 case 0x3a: /* CapsLock */
1356 case 0x45: /* NumLock */
balroga528b802007-10-30 22:38:53 +00001357 if (!down)
1358 vs->modifiers_state[keycode] ^= 1;
1359 break;
1360 }
1361
aliguori753b4052009-02-16 14:59:30 +00001362 if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
balroga528b802007-10-30 22:38:53 +00001363 /* If the numlock state needs to change then simulate an additional
1364 keypress before sending this one. This will happen if the user
1365 toggles numlock away from the VNC window.
1366 */
aliguori753b4052009-02-16 14:59:30 +00001367 if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
balroga528b802007-10-30 22:38:53 +00001368 if (!vs->modifiers_state[0x45]) {
1369 vs->modifiers_state[0x45] = 1;
1370 press_key(vs, 0xff7f);
1371 }
1372 } else {
1373 if (vs->modifiers_state[0x45]) {
1374 vs->modifiers_state[0x45] = 0;
1375 press_key(vs, 0xff7f);
1376 }
1377 }
bellard64f5a132006-08-24 20:36:44 +00001378 }
bellard24236862006-04-30 21:28:36 +00001379
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001380 if ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z')) {
1381 /* If the capslock state needs to change then simulate an additional
1382 keypress before sending this one. This will happen if the user
1383 toggles capslock away from the VNC window.
1384 */
1385 int uppercase = !!(sym >= 'A' && sym <= 'Z');
1386 int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
1387 int capslock = !!(vs->modifiers_state[0x3a]);
1388 if (capslock) {
1389 if (uppercase == shift) {
1390 vs->modifiers_state[0x3a] = 0;
1391 press_key(vs, 0xffe5);
1392 }
1393 } else {
1394 if (uppercase != shift) {
1395 vs->modifiers_state[0x3a] = 1;
1396 press_key(vs, 0xffe5);
1397 }
1398 }
1399 }
1400
bellard64f5a132006-08-24 20:36:44 +00001401 if (is_graphic_console()) {
1402 if (keycode & 0x80)
1403 kbd_put_keycode(0xe0);
1404 if (down)
1405 kbd_put_keycode(keycode & 0x7f);
1406 else
1407 kbd_put_keycode(keycode | 0x80);
1408 } else {
1409 /* QEMU console emulation */
1410 if (down) {
Gerd Hoffmannbb0a18e2009-06-11 11:32:14 +02001411 int numlock = vs->modifiers_state[0x45];
bellard64f5a132006-08-24 20:36:44 +00001412 switch (keycode) {
1413 case 0x2a: /* Left Shift */
1414 case 0x36: /* Right Shift */
1415 case 0x1d: /* Left CTRL */
1416 case 0x9d: /* Right CTRL */
1417 case 0x38: /* Left ALT */
1418 case 0xb8: /* Right ALT */
1419 break;
1420 case 0xc8:
1421 kbd_put_keysym(QEMU_KEY_UP);
1422 break;
1423 case 0xd0:
1424 kbd_put_keysym(QEMU_KEY_DOWN);
1425 break;
1426 case 0xcb:
1427 kbd_put_keysym(QEMU_KEY_LEFT);
1428 break;
1429 case 0xcd:
1430 kbd_put_keysym(QEMU_KEY_RIGHT);
1431 break;
1432 case 0xd3:
1433 kbd_put_keysym(QEMU_KEY_DELETE);
1434 break;
1435 case 0xc7:
1436 kbd_put_keysym(QEMU_KEY_HOME);
1437 break;
1438 case 0xcf:
1439 kbd_put_keysym(QEMU_KEY_END);
1440 break;
1441 case 0xc9:
1442 kbd_put_keysym(QEMU_KEY_PAGEUP);
1443 break;
1444 case 0xd1:
1445 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1446 break;
Gerd Hoffmannbb0a18e2009-06-11 11:32:14 +02001447
1448 case 0x47:
1449 kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
1450 break;
1451 case 0x48:
1452 kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
1453 break;
1454 case 0x49:
1455 kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
1456 break;
1457 case 0x4b:
1458 kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
1459 break;
1460 case 0x4c:
1461 kbd_put_keysym('5');
1462 break;
1463 case 0x4d:
1464 kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
1465 break;
1466 case 0x4f:
1467 kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
1468 break;
1469 case 0x50:
1470 kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
1471 break;
1472 case 0x51:
1473 kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
1474 break;
1475 case 0x52:
1476 kbd_put_keysym('0');
1477 break;
1478 case 0x53:
1479 kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
1480 break;
1481
1482 case 0xb5:
1483 kbd_put_keysym('/');
1484 break;
1485 case 0x37:
1486 kbd_put_keysym('*');
1487 break;
1488 case 0x4a:
1489 kbd_put_keysym('-');
1490 break;
1491 case 0x4e:
1492 kbd_put_keysym('+');
1493 break;
1494 case 0x9c:
1495 kbd_put_keysym('\n');
1496 break;
1497
bellard64f5a132006-08-24 20:36:44 +00001498 default:
1499 kbd_put_keysym(sym);
1500 break;
1501 }
1502 }
1503 }
bellard24236862006-04-30 21:28:36 +00001504}
1505
bellardbdbd7672006-05-01 21:44:22 +00001506static void key_event(VncState *vs, int down, uint32_t sym)
1507{
aliguori9ca313a2008-08-23 23:27:37 +00001508 int keycode;
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001509 int lsym = sym;
aliguori9ca313a2008-08-23 23:27:37 +00001510
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001511 if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) {
1512 lsym = lsym - 'A' + 'a';
1513 }
aliguori9ca313a2008-08-23 23:27:37 +00001514
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001515 keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF);
aliguori9ca313a2008-08-23 23:27:37 +00001516 do_key_event(vs, down, keycode, sym);
1517}
1518
1519static void ext_key_event(VncState *vs, int down,
1520 uint32_t sym, uint16_t keycode)
1521{
1522 /* if the user specifies a keyboard layout, always use it */
1523 if (keyboard_layout)
1524 key_event(vs, down, sym);
1525 else
1526 do_key_event(vs, down, keycode, sym);
bellardbdbd7672006-05-01 21:44:22 +00001527}
1528
bellard24236862006-04-30 21:28:36 +00001529static void framebuffer_update_request(VncState *vs, int incremental,
aliguori28a76be2009-03-06 20:27:40 +00001530 int x_position, int y_position,
1531 int w, int h)
bellard24236862006-04-30 21:28:36 +00001532{
aliguori0e1f5a02008-11-24 19:29:13 +00001533 if (x_position > ds_get_width(vs->ds))
1534 x_position = ds_get_width(vs->ds);
1535 if (y_position > ds_get_height(vs->ds))
1536 y_position = ds_get_height(vs->ds);
1537 if (x_position + w >= ds_get_width(vs->ds))
1538 w = ds_get_width(vs->ds) - x_position;
1539 if (y_position + h >= ds_get_height(vs->ds))
1540 h = ds_get_height(vs->ds) - y_position;
thscf2d3852007-04-29 01:53:20 +00001541
bellard24236862006-04-30 21:28:36 +00001542 int i;
1543 vs->need_update = 1;
1544 if (!incremental) {
Gerd Hoffmann24cf0a62009-04-27 16:39:52 +02001545 vs->force_update = 1;
aliguori28a76be2009-03-06 20:27:40 +00001546 for (i = 0; i < h; i++) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +01001547 vnc_set_bits(vs->dirty[y_position + i],
aliguori6baebed2009-03-20 15:59:14 +00001548 (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
aliguori28a76be2009-03-06 20:27:40 +00001549 }
bellard24236862006-04-30 21:28:36 +00001550 }
1551}
1552
aliguori9ca313a2008-08-23 23:27:37 +00001553static void send_ext_key_event_ack(VncState *vs)
1554{
1555 vnc_write_u8(vs, 0);
1556 vnc_write_u8(vs, 0);
1557 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001558 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1559 VNC_ENCODING_EXT_KEY_EVENT);
aliguori9ca313a2008-08-23 23:27:37 +00001560 vnc_flush(vs);
1561}
1562
malc429a8ed2008-12-01 20:57:48 +00001563static void send_ext_audio_ack(VncState *vs)
1564{
1565 vnc_write_u8(vs, 0);
1566 vnc_write_u8(vs, 0);
1567 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001568 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1569 VNC_ENCODING_AUDIO);
malc429a8ed2008-12-01 20:57:48 +00001570 vnc_flush(vs);
1571}
1572
bellard24236862006-04-30 21:28:36 +00001573static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1574{
1575 int i;
aliguori29fa4ed2009-02-02 15:58:29 +00001576 unsigned int enc = 0;
bellard24236862006-04-30 21:28:36 +00001577
aliguori059cef42009-02-02 15:58:54 +00001578 vnc_zlib_init(vs);
aliguori29fa4ed2009-02-02 15:58:29 +00001579 vs->features = 0;
aliguorifb437312009-02-02 15:58:43 +00001580 vs->vnc_encoding = 0;
1581 vs->tight_compression = 9;
1582 vs->tight_quality = 9;
bellard564c3372007-02-05 20:14:10 +00001583 vs->absolute = -1;
bellard24236862006-04-30 21:28:36 +00001584
1585 for (i = n_encodings - 1; i >= 0; i--) {
aliguori29fa4ed2009-02-02 15:58:29 +00001586 enc = encodings[i];
1587 switch (enc) {
1588 case VNC_ENCODING_RAW:
aliguorifb437312009-02-02 15:58:43 +00001589 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001590 break;
1591 case VNC_ENCODING_COPYRECT:
aliguori753b4052009-02-16 14:59:30 +00001592 vs->features |= VNC_FEATURE_COPYRECT_MASK;
aliguori29fa4ed2009-02-02 15:58:29 +00001593 break;
1594 case VNC_ENCODING_HEXTILE:
1595 vs->features |= VNC_FEATURE_HEXTILE_MASK;
aliguorifb437312009-02-02 15:58:43 +00001596 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001597 break;
aliguori059cef42009-02-02 15:58:54 +00001598 case VNC_ENCODING_ZLIB:
1599 vs->features |= VNC_FEATURE_ZLIB_MASK;
1600 vs->vnc_encoding = enc;
1601 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001602 case VNC_ENCODING_DESKTOPRESIZE:
1603 vs->features |= VNC_FEATURE_RESIZE_MASK;
1604 break;
1605 case VNC_ENCODING_POINTER_TYPE_CHANGE:
1606 vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
1607 break;
1608 case VNC_ENCODING_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00001609 send_ext_key_event_ack(vs);
1610 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001611 case VNC_ENCODING_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00001612 send_ext_audio_ack(vs);
1613 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001614 case VNC_ENCODING_WMVi:
1615 vs->features |= VNC_FEATURE_WMVI_MASK;
aliguorica4cca42008-09-15 16:05:16 +00001616 break;
aliguorifb437312009-02-02 15:58:43 +00001617 case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
1618 vs->tight_compression = (enc & 0x0F);
1619 break;
1620 case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
1621 vs->tight_quality = (enc & 0x0F);
1622 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001623 default:
1624 VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
1625 break;
1626 }
bellard24236862006-04-30 21:28:36 +00001627 }
bellard564c3372007-02-05 20:14:10 +00001628
1629 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001630}
1631
aliguori6cec5482009-01-15 22:17:38 +00001632static void set_pixel_conversion(VncState *vs)
1633{
1634 if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
1635 (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) &&
1636 !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
1637 vs->write_pixels = vnc_write_pixels_copy;
1638 switch (vs->ds->surface->pf.bits_per_pixel) {
1639 case 8:
1640 vs->send_hextile_tile = send_hextile_tile_8;
1641 break;
1642 case 16:
1643 vs->send_hextile_tile = send_hextile_tile_16;
1644 break;
1645 case 32:
1646 vs->send_hextile_tile = send_hextile_tile_32;
1647 break;
1648 }
1649 } else {
1650 vs->write_pixels = vnc_write_pixels_generic;
1651 switch (vs->ds->surface->pf.bits_per_pixel) {
1652 case 8:
1653 vs->send_hextile_tile = send_hextile_tile_generic_8;
1654 break;
1655 case 16:
1656 vs->send_hextile_tile = send_hextile_tile_generic_16;
1657 break;
1658 case 32:
1659 vs->send_hextile_tile = send_hextile_tile_generic_32;
1660 break;
1661 }
1662 }
1663}
1664
bellard24236862006-04-30 21:28:36 +00001665static void set_pixel_format(VncState *vs,
aliguori28a76be2009-03-06 20:27:40 +00001666 int bits_per_pixel, int depth,
1667 int big_endian_flag, int true_color_flag,
1668 int red_max, int green_max, int blue_max,
1669 int red_shift, int green_shift, int blue_shift)
bellard24236862006-04-30 21:28:36 +00001670{
bellard35127792006-05-14 18:11:49 +00001671 if (!true_color_flag) {
aliguori28a76be2009-03-06 20:27:40 +00001672 vnc_client_error(vs);
bellard35127792006-05-14 18:11:49 +00001673 return;
1674 }
aliguori7eac3a82008-09-15 16:03:41 +00001675
Stefano Stabellini1fc62412009-08-03 10:54:32 +01001676 vs->clientds = *(vs->vd->guest.ds);
aliguori6cec5482009-01-15 22:17:38 +00001677 vs->clientds.pf.rmax = red_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001678 count_bits(vs->clientds.pf.rbits, red_max);
aliguori6cec5482009-01-15 22:17:38 +00001679 vs->clientds.pf.rshift = red_shift;
1680 vs->clientds.pf.rmask = red_max << red_shift;
1681 vs->clientds.pf.gmax = green_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001682 count_bits(vs->clientds.pf.gbits, green_max);
aliguori6cec5482009-01-15 22:17:38 +00001683 vs->clientds.pf.gshift = green_shift;
1684 vs->clientds.pf.gmask = green_max << green_shift;
1685 vs->clientds.pf.bmax = blue_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001686 count_bits(vs->clientds.pf.bbits, blue_max);
aliguori6cec5482009-01-15 22:17:38 +00001687 vs->clientds.pf.bshift = blue_shift;
1688 vs->clientds.pf.bmask = blue_max << blue_shift;
1689 vs->clientds.pf.bits_per_pixel = bits_per_pixel;
1690 vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
1691 vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
1692 vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
bellard24236862006-04-30 21:28:36 +00001693
aliguori6cec5482009-01-15 22:17:38 +00001694 set_pixel_conversion(vs);
bellard24236862006-04-30 21:28:36 +00001695
1696 vga_hw_invalidate();
1697 vga_hw_update();
1698}
1699
aliguorica4cca42008-09-15 16:05:16 +00001700static void pixel_format_message (VncState *vs) {
1701 char pad[3] = { 0, 0, 0 };
1702
aliguori6cec5482009-01-15 22:17:38 +00001703 vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
1704 vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
aliguorica4cca42008-09-15 16:05:16 +00001705
Juan Quintelae2542fe2009-07-27 16:13:06 +02001706#ifdef HOST_WORDS_BIGENDIAN
aliguorica4cca42008-09-15 16:05:16 +00001707 vnc_write_u8(vs, 1); /* big-endian-flag */
1708#else
1709 vnc_write_u8(vs, 0); /* big-endian-flag */
1710#endif
1711 vnc_write_u8(vs, 1); /* true-color-flag */
aliguori6cec5482009-01-15 22:17:38 +00001712 vnc_write_u16(vs, vs->ds->surface->pf.rmax); /* red-max */
1713 vnc_write_u16(vs, vs->ds->surface->pf.gmax); /* green-max */
1714 vnc_write_u16(vs, vs->ds->surface->pf.bmax); /* blue-max */
1715 vnc_write_u8(vs, vs->ds->surface->pf.rshift); /* red-shift */
1716 vnc_write_u8(vs, vs->ds->surface->pf.gshift); /* green-shift */
1717 vnc_write_u8(vs, vs->ds->surface->pf.bshift); /* blue-shift */
1718 if (vs->ds->surface->pf.bits_per_pixel == 32)
aliguorica4cca42008-09-15 16:05:16 +00001719 vs->send_hextile_tile = send_hextile_tile_32;
aliguori6cec5482009-01-15 22:17:38 +00001720 else if (vs->ds->surface->pf.bits_per_pixel == 16)
aliguorica4cca42008-09-15 16:05:16 +00001721 vs->send_hextile_tile = send_hextile_tile_16;
aliguori6cec5482009-01-15 22:17:38 +00001722 else if (vs->ds->surface->pf.bits_per_pixel == 8)
aliguorica4cca42008-09-15 16:05:16 +00001723 vs->send_hextile_tile = send_hextile_tile_8;
aliguori6cec5482009-01-15 22:17:38 +00001724 vs->clientds = *(vs->ds->surface);
aurel323cded542009-04-07 19:57:09 +00001725 vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
aliguorica4cca42008-09-15 16:05:16 +00001726 vs->write_pixels = vnc_write_pixels_copy;
1727
1728 vnc_write(vs, pad, 3); /* padding */
1729}
1730
aliguori7d957bd2009-01-15 22:14:11 +00001731static void vnc_dpy_setdata(DisplayState *ds)
1732{
1733 /* We don't have to do anything */
1734}
1735
aliguori753b4052009-02-16 14:59:30 +00001736static void vnc_colordepth(VncState *vs)
aliguori7eac3a82008-09-15 16:03:41 +00001737{
aliguori753b4052009-02-16 14:59:30 +00001738 if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
aliguorica4cca42008-09-15 16:05:16 +00001739 /* Sending a WMVi message to notify the client*/
1740 vnc_write_u8(vs, 0); /* msg id */
1741 vnc_write_u8(vs, 0);
1742 vnc_write_u16(vs, 1); /* number of rects */
aliguori753b4052009-02-16 14:59:30 +00001743 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds),
1744 ds_get_height(vs->ds), VNC_ENCODING_WMVi);
aliguorica4cca42008-09-15 16:05:16 +00001745 pixel_format_message(vs);
1746 vnc_flush(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001747 } else {
aliguori6cec5482009-01-15 22:17:38 +00001748 set_pixel_conversion(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001749 }
1750}
1751
ths60fe76f2007-12-16 03:02:09 +00001752static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001753{
1754 int i;
1755 uint16_t limit;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01001756 VncDisplay *vd = vs->vd;
1757
1758 if (data[0] > 3) {
1759 vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
1760 if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval))
1761 qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
1762 }
bellard24236862006-04-30 21:28:36 +00001763
1764 switch (data[0]) {
1765 case 0:
aliguori28a76be2009-03-06 20:27:40 +00001766 if (len == 1)
1767 return 20;
bellard24236862006-04-30 21:28:36 +00001768
aliguori28a76be2009-03-06 20:27:40 +00001769 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
1770 read_u8(data, 6), read_u8(data, 7),
1771 read_u16(data, 8), read_u16(data, 10),
1772 read_u16(data, 12), read_u8(data, 14),
1773 read_u8(data, 15), read_u8(data, 16));
1774 break;
bellard24236862006-04-30 21:28:36 +00001775 case 2:
aliguori28a76be2009-03-06 20:27:40 +00001776 if (len == 1)
1777 return 4;
bellard24236862006-04-30 21:28:36 +00001778
aliguori28a76be2009-03-06 20:27:40 +00001779 if (len == 4) {
aliguori69dd5c92008-12-22 21:06:23 +00001780 limit = read_u16(data, 2);
1781 if (limit > 0)
1782 return 4 + (limit * 4);
1783 } else
1784 limit = read_u16(data, 2);
bellard24236862006-04-30 21:28:36 +00001785
aliguori28a76be2009-03-06 20:27:40 +00001786 for (i = 0; i < limit; i++) {
1787 int32_t val = read_s32(data, 4 + (i * 4));
1788 memcpy(data + 4 + (i * 4), &val, sizeof(val));
1789 }
bellard24236862006-04-30 21:28:36 +00001790
aliguori28a76be2009-03-06 20:27:40 +00001791 set_encodings(vs, (int32_t *)(data + 4), limit);
1792 break;
bellard24236862006-04-30 21:28:36 +00001793 case 3:
aliguori28a76be2009-03-06 20:27:40 +00001794 if (len == 1)
1795 return 10;
bellard24236862006-04-30 21:28:36 +00001796
aliguori28a76be2009-03-06 20:27:40 +00001797 framebuffer_update_request(vs,
1798 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
1799 read_u16(data, 6), read_u16(data, 8));
1800 break;
bellard24236862006-04-30 21:28:36 +00001801 case 4:
aliguori28a76be2009-03-06 20:27:40 +00001802 if (len == 1)
1803 return 8;
bellard24236862006-04-30 21:28:36 +00001804
aliguori28a76be2009-03-06 20:27:40 +00001805 key_event(vs, read_u8(data, 1), read_u32(data, 4));
1806 break;
bellard24236862006-04-30 21:28:36 +00001807 case 5:
aliguori28a76be2009-03-06 20:27:40 +00001808 if (len == 1)
1809 return 6;
bellard24236862006-04-30 21:28:36 +00001810
aliguori28a76be2009-03-06 20:27:40 +00001811 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
1812 break;
bellard24236862006-04-30 21:28:36 +00001813 case 6:
aliguori28a76be2009-03-06 20:27:40 +00001814 if (len == 1)
1815 return 8;
bellard24236862006-04-30 21:28:36 +00001816
aliguori28a76be2009-03-06 20:27:40 +00001817 if (len == 8) {
thsbaa76662007-09-13 12:41:42 +00001818 uint32_t dlen = read_u32(data, 4);
1819 if (dlen > 0)
1820 return 8 + dlen;
1821 }
bellard24236862006-04-30 21:28:36 +00001822
aliguori28a76be2009-03-06 20:27:40 +00001823 client_cut_text(vs, read_u32(data, 4), data + 8);
1824 break;
aliguori9ca313a2008-08-23 23:27:37 +00001825 case 255:
1826 if (len == 1)
1827 return 2;
1828
1829 switch (read_u8(data, 1)) {
1830 case 0:
1831 if (len == 2)
1832 return 12;
1833
1834 ext_key_event(vs, read_u16(data, 2),
1835 read_u32(data, 4), read_u32(data, 8));
1836 break;
malc429a8ed2008-12-01 20:57:48 +00001837 case 1:
1838 if (len == 2)
1839 return 4;
1840
1841 switch (read_u16 (data, 2)) {
1842 case 0:
1843 audio_add(vs);
1844 break;
1845 case 1:
1846 audio_del(vs);
1847 break;
1848 case 2:
1849 if (len == 4)
1850 return 10;
1851 switch (read_u8(data, 4)) {
1852 case 0: vs->as.fmt = AUD_FMT_U8; break;
1853 case 1: vs->as.fmt = AUD_FMT_S8; break;
1854 case 2: vs->as.fmt = AUD_FMT_U16; break;
1855 case 3: vs->as.fmt = AUD_FMT_S16; break;
1856 case 4: vs->as.fmt = AUD_FMT_U32; break;
1857 case 5: vs->as.fmt = AUD_FMT_S32; break;
1858 default:
1859 printf("Invalid audio format %d\n", read_u8(data, 4));
1860 vnc_client_error(vs);
1861 break;
1862 }
1863 vs->as.nchannels = read_u8(data, 5);
1864 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
1865 printf("Invalid audio channel coount %d\n",
1866 read_u8(data, 5));
1867 vnc_client_error(vs);
1868 break;
1869 }
1870 vs->as.freq = read_u32(data, 6);
1871 break;
1872 default:
1873 printf ("Invalid audio message %d\n", read_u8(data, 4));
1874 vnc_client_error(vs);
1875 break;
1876 }
1877 break;
1878
aliguori9ca313a2008-08-23 23:27:37 +00001879 default:
1880 printf("Msg: %d\n", read_u16(data, 0));
1881 vnc_client_error(vs);
1882 break;
1883 }
1884 break;
bellard24236862006-04-30 21:28:36 +00001885 default:
aliguori28a76be2009-03-06 20:27:40 +00001886 printf("Msg: %d\n", data[0]);
1887 vnc_client_error(vs);
1888 break;
bellard24236862006-04-30 21:28:36 +00001889 }
ths5fafdf22007-09-16 21:08:06 +00001890
bellard24236862006-04-30 21:28:36 +00001891 vnc_read_when(vs, protocol_client_msg, 1);
1892 return 0;
1893}
1894
ths60fe76f2007-12-16 03:02:09 +00001895static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001896{
thsc35734b2007-03-19 15:17:08 +00001897 char buf[1024];
1898 int size;
bellard24236862006-04-30 21:28:36 +00001899
aliguori0e1f5a02008-11-24 19:29:13 +00001900 vnc_write_u16(vs, ds_get_width(vs->ds));
1901 vnc_write_u16(vs, ds_get_height(vs->ds));
bellard24236862006-04-30 21:28:36 +00001902
aliguorica4cca42008-09-15 16:05:16 +00001903 pixel_format_message(vs);
bellard24236862006-04-30 21:28:36 +00001904
thsc35734b2007-03-19 15:17:08 +00001905 if (qemu_name)
1906 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
1907 else
1908 size = snprintf(buf, sizeof(buf), "QEMU");
1909
1910 vnc_write_u32(vs, size);
1911 vnc_write(vs, buf, size);
bellard24236862006-04-30 21:28:36 +00001912 vnc_flush(vs);
1913
1914 vnc_read_when(vs, protocol_client_msg, 1);
1915
1916 return 0;
1917}
1918
aliguori5fb6c7a2009-03-06 20:27:23 +00001919void start_client_init(VncState *vs)
1920{
1921 vnc_read_when(vs, protocol_client_init, 1);
1922}
1923
ths70848512007-08-25 01:37:05 +00001924static void make_challenge(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001925{
ths70848512007-08-25 01:37:05 +00001926 int i;
bellard24236862006-04-30 21:28:36 +00001927
ths70848512007-08-25 01:37:05 +00001928 srand(time(NULL)+getpid()+getpid()*987654+rand());
bellard24236862006-04-30 21:28:36 +00001929
ths70848512007-08-25 01:37:05 +00001930 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
1931 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
1932}
1933
ths60fe76f2007-12-16 03:02:09 +00001934static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00001935{
ths60fe76f2007-12-16 03:02:09 +00001936 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
ths70848512007-08-25 01:37:05 +00001937 int i, j, pwlen;
ths60fe76f2007-12-16 03:02:09 +00001938 unsigned char key[8];
ths70848512007-08-25 01:37:05 +00001939
aliguori753b4052009-02-16 14:59:30 +00001940 if (!vs->vd->password || !vs->vd->password[0]) {
aliguori28a76be2009-03-06 20:27:40 +00001941 VNC_DEBUG("No password configured on server");
1942 vnc_write_u32(vs, 1); /* Reject auth */
1943 if (vs->minor >= 8) {
1944 static const char err[] = "Authentication failed";
1945 vnc_write_u32(vs, sizeof(err));
1946 vnc_write(vs, err, sizeof(err));
1947 }
1948 vnc_flush(vs);
1949 vnc_client_error(vs);
1950 return 0;
bellard24236862006-04-30 21:28:36 +00001951 }
1952
ths70848512007-08-25 01:37:05 +00001953 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
1954
1955 /* Calculate the expected challenge response */
aliguori753b4052009-02-16 14:59:30 +00001956 pwlen = strlen(vs->vd->password);
ths70848512007-08-25 01:37:05 +00001957 for (i=0; i<sizeof(key); i++)
aliguori753b4052009-02-16 14:59:30 +00001958 key[i] = i<pwlen ? vs->vd->password[i] : 0;
ths70848512007-08-25 01:37:05 +00001959 deskey(key, EN0);
1960 for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
1961 des(response+j, response+j);
1962
1963 /* Compare expected vs actual challenge response */
1964 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
aliguori28a76be2009-03-06 20:27:40 +00001965 VNC_DEBUG("Client challenge reponse did not match\n");
1966 vnc_write_u32(vs, 1); /* Reject auth */
1967 if (vs->minor >= 8) {
1968 static const char err[] = "Authentication failed";
1969 vnc_write_u32(vs, sizeof(err));
1970 vnc_write(vs, err, sizeof(err));
1971 }
1972 vnc_flush(vs);
1973 vnc_client_error(vs);
ths70848512007-08-25 01:37:05 +00001974 } else {
aliguori28a76be2009-03-06 20:27:40 +00001975 VNC_DEBUG("Accepting VNC challenge response\n");
1976 vnc_write_u32(vs, 0); /* Accept auth */
1977 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00001978
aliguori5fb6c7a2009-03-06 20:27:23 +00001979 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00001980 }
1981 return 0;
1982}
1983
aliguori5fb6c7a2009-03-06 20:27:23 +00001984void start_auth_vnc(VncState *vs)
ths70848512007-08-25 01:37:05 +00001985{
1986 make_challenge(vs);
1987 /* Send client a 'random' challenge */
1988 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
bellard24236862006-04-30 21:28:36 +00001989 vnc_flush(vs);
1990
ths70848512007-08-25 01:37:05 +00001991 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
ths70848512007-08-25 01:37:05 +00001992}
1993
ths8d5d2d42007-08-25 01:37:51 +00001994
ths60fe76f2007-12-16 03:02:09 +00001995static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00001996{
1997 /* We only advertise 1 auth scheme at a time, so client
1998 * must pick the one we sent. Verify this */
aliguori753b4052009-02-16 14:59:30 +00001999 if (data[0] != vs->vd->auth) { /* Reject auth */
aliguori1263b7d2009-03-06 20:27:32 +00002000 VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
ths70848512007-08-25 01:37:05 +00002001 vnc_write_u32(vs, 1);
2002 if (vs->minor >= 8) {
2003 static const char err[] = "Authentication failed";
2004 vnc_write_u32(vs, sizeof(err));
2005 vnc_write(vs, err, sizeof(err));
2006 }
2007 vnc_client_error(vs);
2008 } else { /* Accept requested auth */
2009 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
aliguori753b4052009-02-16 14:59:30 +00002010 switch (vs->vd->auth) {
ths70848512007-08-25 01:37:05 +00002011 case VNC_AUTH_NONE:
2012 VNC_DEBUG("Accept auth none\n");
balroga26c97a2007-10-31 01:58:56 +00002013 if (vs->minor >= 8) {
2014 vnc_write_u32(vs, 0); /* Accept auth completion */
2015 vnc_flush(vs);
2016 }
aliguori5fb6c7a2009-03-06 20:27:23 +00002017 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00002018 break;
2019
2020 case VNC_AUTH_VNC:
2021 VNC_DEBUG("Start VNC auth\n");
aliguori5fb6c7a2009-03-06 20:27:23 +00002022 start_auth_vnc(vs);
2023 break;
ths70848512007-08-25 01:37:05 +00002024
blueswir1eb38c522008-09-06 17:47:39 +00002025#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002026 case VNC_AUTH_VENCRYPT:
2027 VNC_DEBUG("Accept VeNCrypt auth\n");;
aliguori5fb6c7a2009-03-06 20:27:23 +00002028 start_auth_vencrypt(vs);
2029 break;
ths8d5d2d42007-08-25 01:37:51 +00002030#endif /* CONFIG_VNC_TLS */
2031
aliguori2f9606b2009-03-06 20:27:28 +00002032#ifdef CONFIG_VNC_SASL
2033 case VNC_AUTH_SASL:
2034 VNC_DEBUG("Accept SASL auth\n");
2035 start_auth_sasl(vs);
2036 break;
2037#endif /* CONFIG_VNC_SASL */
2038
ths70848512007-08-25 01:37:05 +00002039 default: /* Should not be possible, but just in case */
aliguori1263b7d2009-03-06 20:27:32 +00002040 VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002041 vnc_write_u8(vs, 1);
2042 if (vs->minor >= 8) {
2043 static const char err[] = "Authentication failed";
2044 vnc_write_u32(vs, sizeof(err));
2045 vnc_write(vs, err, sizeof(err));
2046 }
2047 vnc_client_error(vs);
2048 }
2049 }
2050 return 0;
2051}
2052
ths60fe76f2007-12-16 03:02:09 +00002053static int protocol_version(VncState *vs, uint8_t *version, size_t len)
ths70848512007-08-25 01:37:05 +00002054{
2055 char local[13];
2056
2057 memcpy(local, version, 12);
2058 local[12] = 0;
2059
2060 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
aliguori28a76be2009-03-06 20:27:40 +00002061 VNC_DEBUG("Malformed protocol version %s\n", local);
2062 vnc_client_error(vs);
2063 return 0;
ths70848512007-08-25 01:37:05 +00002064 }
2065 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2066 if (vs->major != 3 ||
aliguori28a76be2009-03-06 20:27:40 +00002067 (vs->minor != 3 &&
2068 vs->minor != 4 &&
2069 vs->minor != 5 &&
2070 vs->minor != 7 &&
2071 vs->minor != 8)) {
2072 VNC_DEBUG("Unsupported client version\n");
2073 vnc_write_u32(vs, VNC_AUTH_INVALID);
2074 vnc_flush(vs);
2075 vnc_client_error(vs);
2076 return 0;
ths70848512007-08-25 01:37:05 +00002077 }
thsb0566f42007-09-30 13:01:15 +00002078 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
ths70848512007-08-25 01:37:05 +00002079 * as equivalent to v3.3 by servers
2080 */
thsb0566f42007-09-30 13:01:15 +00002081 if (vs->minor == 4 || vs->minor == 5)
aliguori28a76be2009-03-06 20:27:40 +00002082 vs->minor = 3;
ths70848512007-08-25 01:37:05 +00002083
2084 if (vs->minor == 3) {
aliguori28a76be2009-03-06 20:27:40 +00002085 if (vs->vd->auth == VNC_AUTH_NONE) {
ths70848512007-08-25 01:37:05 +00002086 VNC_DEBUG("Tell client auth none\n");
aliguori753b4052009-02-16 14:59:30 +00002087 vnc_write_u32(vs, vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002088 vnc_flush(vs);
aliguori28a76be2009-03-06 20:27:40 +00002089 start_client_init(vs);
aliguori753b4052009-02-16 14:59:30 +00002090 } else if (vs->vd->auth == VNC_AUTH_VNC) {
ths70848512007-08-25 01:37:05 +00002091 VNC_DEBUG("Tell client VNC auth\n");
aliguori753b4052009-02-16 14:59:30 +00002092 vnc_write_u32(vs, vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002093 vnc_flush(vs);
2094 start_auth_vnc(vs);
2095 } else {
aliguori753b4052009-02-16 14:59:30 +00002096 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002097 vnc_write_u32(vs, VNC_AUTH_INVALID);
2098 vnc_flush(vs);
2099 vnc_client_error(vs);
2100 }
2101 } else {
aliguori28a76be2009-03-06 20:27:40 +00002102 VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
2103 vnc_write_u8(vs, 1); /* num auth */
2104 vnc_write_u8(vs, vs->vd->auth);
2105 vnc_read_when(vs, protocol_client_auth, 1);
2106 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002107 }
bellard24236862006-04-30 21:28:36 +00002108
2109 return 0;
2110}
2111
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002112static int vnc_refresh_server_surface(VncDisplay *vd)
2113{
2114 int y;
2115 uint8_t *guest_row;
2116 uint8_t *server_row;
2117 int cmp_bytes;
2118 uint32_t width_mask[VNC_DIRTY_WORDS];
2119 VncState *vs = NULL;
2120 int has_dirty = 0;
2121
2122 /*
2123 * Walk through the guest dirty map.
2124 * Check and copy modified bits from guest to server surface.
2125 * Update server dirty map.
2126 */
2127 vnc_set_bits(width_mask, (ds_get_width(vd->ds) / 16), VNC_DIRTY_WORDS);
2128 cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
2129 guest_row = vd->guest.ds->data;
2130 server_row = vd->server->data;
2131 for (y = 0; y < vd->guest.ds->height; y++) {
2132 if (vnc_and_bits(vd->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
2133 int x;
2134 uint8_t *guest_ptr;
2135 uint8_t *server_ptr;
2136
2137 guest_ptr = guest_row;
2138 server_ptr = server_row;
2139
2140 for (x = 0; x < vd->guest.ds->width;
2141 x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
2142 if (!vnc_get_bit(vd->guest.dirty[y], (x / 16)))
2143 continue;
2144 vnc_clear_bit(vd->guest.dirty[y], (x / 16));
2145 if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
2146 continue;
2147 memcpy(server_ptr, guest_ptr, cmp_bytes);
2148 vs = vd->clients;
2149 while (vs != NULL) {
2150 vnc_set_bit(vs->dirty[y], (x / 16));
2151 vs = vs->next;
2152 }
2153 has_dirty++;
2154 }
2155 }
2156 guest_row += ds_get_linesize(vd->ds);
2157 server_row += ds_get_linesize(vd->ds);
2158 }
2159 return has_dirty;
2160}
2161
Stefano Stabellini703bc682009-08-03 10:54:05 +01002162static void vnc_refresh(void *opaque)
2163{
2164 VncDisplay *vd = opaque;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002165 VncState *vs = NULL;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002166 int has_dirty = 0, rects = 0;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002167
2168 vga_hw_update();
2169
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002170 has_dirty = vnc_refresh_server_surface(vd);
2171
2172 vs = vd->clients;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002173 while (vs != NULL) {
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002174 rects += vnc_update_client(vs, has_dirty);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002175 vs = vs->next;
2176 }
2177
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002178 if (has_dirty && rects) {
2179 vd->timer_interval /= 2;
2180 if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE)
2181 vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
2182 } else {
2183 vd->timer_interval += VNC_REFRESH_INTERVAL_INC;
2184 if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
2185 vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
2186 }
2187 qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002188}
2189
2190static void vnc_init_timer(VncDisplay *vd)
2191{
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002192 vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002193 if (vd->timer == NULL && vd->clients != NULL) {
2194 vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002195 vnc_refresh(vd);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002196 }
2197}
2198
2199static void vnc_remove_timer(VncDisplay *vd)
2200{
2201 if (vd->timer != NULL && vd->clients == NULL) {
2202 qemu_del_timer(vd->timer);
2203 qemu_free_timer(vd->timer);
2204 vd->timer = NULL;
2205 }
2206}
2207
aliguori753b4052009-02-16 14:59:30 +00002208static void vnc_connect(VncDisplay *vd, int csock)
balrog3aa3eea2008-02-03 02:54:04 +00002209{
aliguori753b4052009-02-16 14:59:30 +00002210 VncState *vs = qemu_mallocz(sizeof(VncState));
2211 vs->csock = csock;
2212
2213 VNC_DEBUG("New client on socket %d\n", csock);
aliguori7d957bd2009-01-15 22:14:11 +00002214 dcl->idle = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002215 socket_set_nonblock(vs->csock);
2216 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
aliguori753b4052009-02-16 14:59:30 +00002217
2218 vs->vd = vd;
2219 vs->ds = vd->ds;
aliguori753b4052009-02-16 14:59:30 +00002220 vs->last_x = -1;
2221 vs->last_y = -1;
2222
2223 vs->as.freq = 44100;
2224 vs->as.nchannels = 2;
2225 vs->as.fmt = AUD_FMT_S16;
2226 vs->as.endianness = 0;
2227
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002228 vs->next = vd->clients;
2229 vd->clients = vs;
2230
2231 vga_hw_update();
2232
balrog3aa3eea2008-02-03 02:54:04 +00002233 vnc_write(vs, "RFB 003.008\n", 12);
2234 vnc_flush(vs);
2235 vnc_read_when(vs, protocol_version, 12);
malc53762dd2008-12-01 20:57:52 +00002236 reset_keys(vs);
aliguori753b4052009-02-16 14:59:30 +00002237
Stefano Stabellini703bc682009-08-03 10:54:05 +01002238 vnc_init_timer(vd);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002239
Gerd Hoffmann198a0032009-06-16 14:19:48 +02002240 /* vs might be free()ed here */
balrog3aa3eea2008-02-03 02:54:04 +00002241}
2242
bellard24236862006-04-30 21:28:36 +00002243static void vnc_listen_read(void *opaque)
2244{
aliguori753b4052009-02-16 14:59:30 +00002245 VncDisplay *vs = opaque;
bellard24236862006-04-30 21:28:36 +00002246 struct sockaddr_in addr;
2247 socklen_t addrlen = sizeof(addr);
2248
balrog9f60ad52008-01-14 21:45:55 +00002249 /* Catch-up */
2250 vga_hw_update();
2251
Kevin Wolf40ff6d72009-12-02 12:24:42 +01002252 int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
aliguori753b4052009-02-16 14:59:30 +00002253 if (csock != -1) {
2254 vnc_connect(vs, csock);
bellard24236862006-04-30 21:28:36 +00002255 }
2256}
2257
ths71cab5c2007-08-25 01:35:38 +00002258void vnc_display_init(DisplayState *ds)
bellard24236862006-04-30 21:28:36 +00002259{
Stefan Weilafd32162009-05-24 22:33:34 +02002260 VncDisplay *vs = qemu_mallocz(sizeof(*vs));
bellard24236862006-04-30 21:28:36 +00002261
aliguori7d957bd2009-01-15 22:14:11 +00002262 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
bellard24236862006-04-30 21:28:36 +00002263
2264 ds->opaque = vs;
aliguori7d957bd2009-01-15 22:14:11 +00002265 dcl->idle = 1;
aliguori753b4052009-02-16 14:59:30 +00002266 vnc_display = vs;
bellard24236862006-04-30 21:28:36 +00002267
2268 vs->lsock = -1;
bellard24236862006-04-30 21:28:36 +00002269
2270 vs->ds = ds;
2271
aliguori9ca313a2008-08-23 23:27:37 +00002272 if (keyboard_layout)
aliguori04837552009-03-06 20:27:10 +00002273 vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
aliguori9ca313a2008-08-23 23:27:37 +00002274 else
aliguori04837552009-03-06 20:27:10 +00002275 vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
bellard24236862006-04-30 21:28:36 +00002276
bellard24236862006-04-30 21:28:36 +00002277 if (!vs->kbd_layout)
aliguori28a76be2009-03-06 20:27:40 +00002278 exit(1);
bellard24236862006-04-30 21:28:36 +00002279
aliguori753b4052009-02-16 14:59:30 +00002280 dcl->dpy_copy = vnc_dpy_copy;
aliguori7d957bd2009-01-15 22:14:11 +00002281 dcl->dpy_update = vnc_dpy_update;
2282 dcl->dpy_resize = vnc_dpy_resize;
2283 dcl->dpy_setdata = vnc_dpy_setdata;
aliguori7d957bd2009-01-15 22:14:11 +00002284 register_displaychangelistener(ds, dcl);
ths71cab5c2007-08-25 01:35:38 +00002285}
ths73fc9742006-12-22 02:09:07 +00002286
ths6f430242007-08-25 01:39:57 +00002287
ths71cab5c2007-08-25 01:35:38 +00002288void vnc_display_close(DisplayState *ds)
2289{
aliguori753b4052009-02-16 14:59:30 +00002290 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths71cab5c2007-08-25 01:35:38 +00002291
aliguori452b4d82009-02-11 21:00:38 +00002292 if (!vs)
2293 return;
ths71cab5c2007-08-25 01:35:38 +00002294 if (vs->display) {
aliguori28a76be2009-03-06 20:27:40 +00002295 qemu_free(vs->display);
2296 vs->display = NULL;
ths71cab5c2007-08-25 01:35:38 +00002297 }
2298 if (vs->lsock != -1) {
aliguori28a76be2009-03-06 20:27:40 +00002299 qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
2300 close(vs->lsock);
2301 vs->lsock = -1;
ths71cab5c2007-08-25 01:35:38 +00002302 }
ths70848512007-08-25 01:37:05 +00002303 vs->auth = VNC_AUTH_INVALID;
blueswir1eb38c522008-09-06 17:47:39 +00002304#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002305 vs->subauth = VNC_AUTH_INVALID;
aliguori5fb6c7a2009-03-06 20:27:23 +00002306 vs->tls.x509verify = 0;
ths8d5d2d42007-08-25 01:37:51 +00002307#endif
ths71cab5c2007-08-25 01:35:38 +00002308}
2309
ths70848512007-08-25 01:37:05 +00002310int vnc_display_password(DisplayState *ds, const char *password)
2311{
aliguori753b4052009-02-16 14:59:30 +00002312 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths70848512007-08-25 01:37:05 +00002313
Zachary Amsden7ef92332009-07-30 00:15:00 -10002314 if (!vs) {
2315 return -1;
2316 }
2317
ths70848512007-08-25 01:37:05 +00002318 if (vs->password) {
aliguori28a76be2009-03-06 20:27:40 +00002319 qemu_free(vs->password);
2320 vs->password = NULL;
ths70848512007-08-25 01:37:05 +00002321 }
2322 if (password && password[0]) {
aliguori28a76be2009-03-06 20:27:40 +00002323 if (!(vs->password = qemu_strdup(password)))
2324 return -1;
Zachary Amsden52c18be2009-07-30 00:15:01 -10002325 if (vs->auth == VNC_AUTH_NONE) {
2326 vs->auth = VNC_AUTH_VNC;
2327 }
2328 } else {
2329 vs->auth = VNC_AUTH_NONE;
ths70848512007-08-25 01:37:05 +00002330 }
2331
2332 return 0;
2333}
2334
Anthony Liguorif92f8af2009-05-20 13:01:02 -05002335char *vnc_display_local_addr(DisplayState *ds)
2336{
2337 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
2338
2339 return vnc_socket_local_addr("%s:%s", vs->lsock);
2340}
2341
ths70848512007-08-25 01:37:05 +00002342int vnc_display_open(DisplayState *ds, const char *display)
ths71cab5c2007-08-25 01:35:38 +00002343{
aliguori753b4052009-02-16 14:59:30 +00002344 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths70848512007-08-25 01:37:05 +00002345 const char *options;
2346 int password = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002347 int reverse = 0;
aliguori9712eca2008-11-11 20:51:59 +00002348 int to_port = 0;
blueswir1eb38c522008-09-06 17:47:39 +00002349#ifdef CONFIG_VNC_TLS
ths3a702692007-08-25 01:38:36 +00002350 int tls = 0, x509 = 0;
ths8d5d2d42007-08-25 01:37:51 +00002351#endif
aliguori2f9606b2009-03-06 20:27:28 +00002352#ifdef CONFIG_VNC_SASL
2353 int sasl = 0;
2354 int saslErr;
2355#endif
aliguori76655d62009-03-06 20:27:37 +00002356 int acl = 0;
ths71cab5c2007-08-25 01:35:38 +00002357
aliguori753b4052009-02-16 14:59:30 +00002358 if (!vnc_display)
aliguori452b4d82009-02-11 21:00:38 +00002359 return -1;
ths71cab5c2007-08-25 01:35:38 +00002360 vnc_display_close(ds);
ths70848512007-08-25 01:37:05 +00002361 if (strcmp(display, "none") == 0)
aliguori28a76be2009-03-06 20:27:40 +00002362 return 0;
ths71cab5c2007-08-25 01:35:38 +00002363
ths70848512007-08-25 01:37:05 +00002364 if (!(vs->display = strdup(display)))
aliguori28a76be2009-03-06 20:27:40 +00002365 return -1;
ths70848512007-08-25 01:37:05 +00002366
2367 options = display;
2368 while ((options = strchr(options, ','))) {
aliguori28a76be2009-03-06 20:27:40 +00002369 options++;
2370 if (strncmp(options, "password", 8) == 0) {
2371 password = 1; /* Require password auth */
2372 } else if (strncmp(options, "reverse", 7) == 0) {
2373 reverse = 1;
2374 } else if (strncmp(options, "to=", 3) == 0) {
aliguori9712eca2008-11-11 20:51:59 +00002375 to_port = atoi(options+3) + 5900;
aliguori2f9606b2009-03-06 20:27:28 +00002376#ifdef CONFIG_VNC_SASL
aliguori28a76be2009-03-06 20:27:40 +00002377 } else if (strncmp(options, "sasl", 4) == 0) {
2378 sasl = 1; /* Require SASL auth */
aliguori2f9606b2009-03-06 20:27:28 +00002379#endif
blueswir1eb38c522008-09-06 17:47:39 +00002380#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002381 } else if (strncmp(options, "tls", 3) == 0) {
2382 tls = 1; /* Require TLS */
2383 } else if (strncmp(options, "x509", 4) == 0) {
2384 char *start, *end;
2385 x509 = 1; /* Require x509 certificates */
2386 if (strncmp(options, "x509verify", 10) == 0)
2387 vs->tls.x509verify = 1; /* ...and verify client certs */
ths6f430242007-08-25 01:39:57 +00002388
aliguori28a76be2009-03-06 20:27:40 +00002389 /* Now check for 'x509=/some/path' postfix
2390 * and use that to setup x509 certificate/key paths */
2391 start = strchr(options, '=');
2392 end = strchr(options, ',');
2393 if (start && (!end || (start < end))) {
2394 int len = end ? end-(start+1) : strlen(start+1);
2395 char *path = qemu_strndup(start + 1, len);
blueswir1be15b142008-10-25 11:21:28 +00002396
aliguori28a76be2009-03-06 20:27:40 +00002397 VNC_DEBUG("Trying certificate path '%s'\n", path);
2398 if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
2399 fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
2400 qemu_free(path);
2401 qemu_free(vs->display);
2402 vs->display = NULL;
2403 return -1;
2404 }
2405 qemu_free(path);
2406 } else {
2407 fprintf(stderr, "No certificate path provided\n");
2408 qemu_free(vs->display);
2409 vs->display = NULL;
2410 return -1;
2411 }
ths8d5d2d42007-08-25 01:37:51 +00002412#endif
aliguori28a76be2009-03-06 20:27:40 +00002413 } else if (strncmp(options, "acl", 3) == 0) {
2414 acl = 1;
2415 }
ths70848512007-08-25 01:37:05 +00002416 }
2417
aliguori76655d62009-03-06 20:27:37 +00002418#ifdef CONFIG_VNC_TLS
2419 if (acl && x509 && vs->tls.x509verify) {
aliguori28a76be2009-03-06 20:27:40 +00002420 if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
2421 fprintf(stderr, "Failed to create x509 dname ACL\n");
2422 exit(1);
2423 }
aliguori76655d62009-03-06 20:27:37 +00002424 }
2425#endif
2426#ifdef CONFIG_VNC_SASL
2427 if (acl && sasl) {
aliguori28a76be2009-03-06 20:27:40 +00002428 if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
2429 fprintf(stderr, "Failed to create username ACL\n");
2430 exit(1);
2431 }
aliguori76655d62009-03-06 20:27:37 +00002432 }
2433#endif
2434
aliguori2f9606b2009-03-06 20:27:28 +00002435 /*
2436 * Combinations we support here:
2437 *
2438 * - no-auth (clear text, no auth)
2439 * - password (clear text, weak auth)
2440 * - sasl (encrypt, good auth *IF* using Kerberos via GSSAPI)
2441 * - tls (encrypt, weak anonymous creds, no auth)
2442 * - tls + password (encrypt, weak anonymous creds, weak auth)
2443 * - tls + sasl (encrypt, weak anonymous creds, good auth)
2444 * - tls + x509 (encrypt, good x509 creds, no auth)
2445 * - tls + x509 + password (encrypt, good x509 creds, weak auth)
2446 * - tls + x509 + sasl (encrypt, good x509 creds, good auth)
2447 *
2448 * NB1. TLS is a stackable auth scheme.
2449 * NB2. the x509 schemes have option to validate a client cert dname
2450 */
ths70848512007-08-25 01:37:05 +00002451 if (password) {
blueswir1eb38c522008-09-06 17:47:39 +00002452#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002453 if (tls) {
2454 vs->auth = VNC_AUTH_VENCRYPT;
2455 if (x509) {
2456 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
2457 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
2458 } else {
2459 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
2460 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
2461 }
2462 } else {
aliguori2f9606b2009-03-06 20:27:28 +00002463#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00002464 VNC_DEBUG("Initializing VNC server with password auth\n");
2465 vs->auth = VNC_AUTH_VNC;
blueswir1eb38c522008-09-06 17:47:39 +00002466#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002467 vs->subauth = VNC_AUTH_INVALID;
2468 }
aliguori2f9606b2009-03-06 20:27:28 +00002469#endif /* CONFIG_VNC_TLS */
2470#ifdef CONFIG_VNC_SASL
2471 } else if (sasl) {
2472#ifdef CONFIG_VNC_TLS
2473 if (tls) {
2474 vs->auth = VNC_AUTH_VENCRYPT;
2475 if (x509) {
aliguori28a76be2009-03-06 20:27:40 +00002476 VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00002477 vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
2478 } else {
aliguori28a76be2009-03-06 20:27:40 +00002479 VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00002480 vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
2481 }
2482 } else {
2483#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00002484 VNC_DEBUG("Initializing VNC server with SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00002485 vs->auth = VNC_AUTH_SASL;
2486#ifdef CONFIG_VNC_TLS
2487 vs->subauth = VNC_AUTH_INVALID;
2488 }
2489#endif /* CONFIG_VNC_TLS */
2490#endif /* CONFIG_VNC_SASL */
ths70848512007-08-25 01:37:05 +00002491 } else {
blueswir1eb38c522008-09-06 17:47:39 +00002492#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002493 if (tls) {
2494 vs->auth = VNC_AUTH_VENCRYPT;
2495 if (x509) {
2496 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
2497 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
2498 } else {
2499 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
2500 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
2501 }
2502 } else {
ths8d5d2d42007-08-25 01:37:51 +00002503#endif
aliguori28a76be2009-03-06 20:27:40 +00002504 VNC_DEBUG("Initializing VNC server with no auth\n");
2505 vs->auth = VNC_AUTH_NONE;
blueswir1eb38c522008-09-06 17:47:39 +00002506#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002507 vs->subauth = VNC_AUTH_INVALID;
2508 }
ths8d5d2d42007-08-25 01:37:51 +00002509#endif
ths70848512007-08-25 01:37:05 +00002510 }
bellard24236862006-04-30 21:28:36 +00002511
aliguori2f9606b2009-03-06 20:27:28 +00002512#ifdef CONFIG_VNC_SASL
2513 if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
2514 fprintf(stderr, "Failed to initialize SASL auth %s",
2515 sasl_errstring(saslErr, NULL, NULL));
2516 free(vs->display);
2517 vs->display = NULL;
2518 return -1;
2519 }
2520#endif
2521
balrog3aa3eea2008-02-03 02:54:04 +00002522 if (reverse) {
aliguori9712eca2008-11-11 20:51:59 +00002523 /* connect to viewer */
2524 if (strncmp(display, "unix:", 5) == 0)
2525 vs->lsock = unix_connect(display+5);
2526 else
2527 vs->lsock = inet_connect(display, SOCK_STREAM);
2528 if (-1 == vs->lsock) {
balrog3aa3eea2008-02-03 02:54:04 +00002529 free(vs->display);
2530 vs->display = NULL;
2531 return -1;
2532 } else {
aliguori753b4052009-02-16 14:59:30 +00002533 int csock = vs->lsock;
balrog3aa3eea2008-02-03 02:54:04 +00002534 vs->lsock = -1;
aliguori753b4052009-02-16 14:59:30 +00002535 vnc_connect(vs, csock);
balrog3aa3eea2008-02-03 02:54:04 +00002536 }
aliguori9712eca2008-11-11 20:51:59 +00002537 return 0;
balrog3aa3eea2008-02-03 02:54:04 +00002538
aliguori9712eca2008-11-11 20:51:59 +00002539 } else {
2540 /* listen for connects */
2541 char *dpy;
2542 dpy = qemu_malloc(256);
2543 if (strncmp(display, "unix:", 5) == 0) {
blueswir1bc575e92009-01-14 18:34:22 +00002544 pstrcpy(dpy, 256, "unix:");
aliguori4a55bfd2008-12-02 20:02:14 +00002545 vs->lsock = unix_listen(display+5, dpy+5, 256-5);
aliguori9712eca2008-11-11 20:51:59 +00002546 } else {
2547 vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
2548 }
2549 if (-1 == vs->lsock) {
2550 free(dpy);
balrogd0513622008-12-01 01:48:36 +00002551 return -1;
aliguori9712eca2008-11-11 20:51:59 +00002552 } else {
2553 free(vs->display);
2554 vs->display = dpy;
2555 }
bellard24236862006-04-30 21:28:36 +00002556 }
aliguori753b4052009-02-16 14:59:30 +00002557 return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00002558}