blob: 42c92ed36b164a0fd97752d9a789967fb20973a3 [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
aliguori059cef42009-02-02 15:58:54 +0000541static void vnc_zlib_init(VncState *vs)
542{
543 int i;
544 for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++)
545 vs->zlib_stream[i].opaque = NULL;
546}
547
548static void vnc_zlib_start(VncState *vs)
549{
550 buffer_reset(&vs->zlib);
551
552 // make the output buffer be the zlib buffer, so we can compress it later
553 vs->zlib_tmp = vs->output;
554 vs->output = vs->zlib;
555}
556
557static int vnc_zlib_stop(VncState *vs, int stream_id)
558{
559 z_streamp zstream = &vs->zlib_stream[stream_id];
560 int previous_out;
561
562 // switch back to normal output/zlib buffers
563 vs->zlib = vs->output;
564 vs->output = vs->zlib_tmp;
565
566 // compress the zlib buffer
567
568 // initialize the stream
569 // XXX need one stream per session
570 if (zstream->opaque != vs) {
571 int err;
572
573 VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
574 VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
575 zstream->zalloc = Z_NULL;
576 zstream->zfree = Z_NULL;
577
578 err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
579 MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
580
581 if (err != Z_OK) {
582 fprintf(stderr, "VNC: error initializing zlib\n");
583 return -1;
584 }
585
586 zstream->opaque = vs;
587 }
588
589 // XXX what to do if tight_compression changed in between?
590
591 // reserve memory in output buffer
592 buffer_reserve(&vs->output, vs->zlib.offset + 64);
593
594 // set pointers
595 zstream->next_in = vs->zlib.buffer;
596 zstream->avail_in = vs->zlib.offset;
597 zstream->next_out = vs->output.buffer + vs->output.offset;
598 zstream->avail_out = vs->output.capacity - vs->output.offset;
599 zstream->data_type = Z_BINARY;
600 previous_out = zstream->total_out;
601
602 // start encoding
603 if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
604 fprintf(stderr, "VNC: error during zlib compression\n");
605 return -1;
606 }
607
608 vs->output.offset = vs->output.capacity - zstream->avail_out;
609 return zstream->total_out - previous_out;
610}
611
612static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h)
613{
614 int old_offset, new_offset, bytes_written;
615
616 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
617
618 // remember where we put in the follow-up size
619 old_offset = vs->output.offset;
620 vnc_write_s32(vs, 0);
621
622 // compress the stream
623 vnc_zlib_start(vs);
624 send_framebuffer_update_raw(vs, x, y, w, h);
625 bytes_written = vnc_zlib_stop(vs, 0);
626
627 if (bytes_written == -1)
628 return;
629
630 // hack in the size
631 new_offset = vs->output.offset;
632 vs->output.offset = old_offset;
633 vnc_write_u32(vs, bytes_written);
634 vs->output.offset = new_offset;
635}
636
bellard24236862006-04-30 21:28:36 +0000637static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
638{
aliguorifb437312009-02-02 15:58:43 +0000639 switch(vs->vnc_encoding) {
aliguori28a76be2009-03-06 20:27:40 +0000640 case VNC_ENCODING_ZLIB:
641 send_framebuffer_update_zlib(vs, x, y, w, h);
642 break;
643 case VNC_ENCODING_HEXTILE:
644 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
645 send_framebuffer_update_hextile(vs, x, y, w, h);
646 break;
647 default:
648 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
649 send_framebuffer_update_raw(vs, x, y, w, h);
650 break;
aliguorifb437312009-02-02 15:58:43 +0000651 }
bellard24236862006-04-30 21:28:36 +0000652}
653
aliguori753b4052009-02-16 14:59:30 +0000654static 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 +0000655{
Gerd Hoffmann3e28c9a2009-07-27 17:10:48 +0200656 /* send bitblit op to the vnc client */
bellard24236862006-04-30 21:28:36 +0000657 vnc_write_u8(vs, 0); /* msg id */
658 vnc_write_u8(vs, 0);
659 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000660 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
bellard24236862006-04-30 21:28:36 +0000661 vnc_write_u16(vs, src_x);
662 vnc_write_u16(vs, src_y);
663 vnc_flush(vs);
664}
665
aliguori753b4052009-02-16 14:59:30 +0000666static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
667{
668 VncDisplay *vd = ds->opaque;
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200669 VncState *vs, *vn;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100670 uint8_t *src_row;
671 uint8_t *dst_row;
672 int i,x,y,pitch,depth,inc,w_lim,s;
673 int cmp_bytes;
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200674
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100675 vnc_refresh_server_surface(vd);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200676 for (vs = vd->clients; vs != NULL; vs = vn) {
677 vn = vs->next;
678 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
679 vs->force_update = 1;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100680 vnc_update_client(vs, 1);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200681 /* vs might be free()ed here */
682 }
683 }
684
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100685 /* do bitblit op on the local surface too */
686 pitch = ds_get_linesize(vd->ds);
687 depth = ds_get_bytes_per_pixel(vd->ds);
688 src_row = vd->server->data + pitch * src_y + depth * src_x;
689 dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
690 y = dst_y;
691 inc = 1;
692 if (dst_y > src_y) {
693 /* copy backwards */
694 src_row += pitch * (h-1);
695 dst_row += pitch * (h-1);
696 pitch = -pitch;
697 y = dst_y + h - 1;
698 inc = -1;
699 }
700 w_lim = w - (16 - (dst_x % 16));
701 if (w_lim < 0)
702 w_lim = w;
703 else
704 w_lim = w - (w_lim % 16);
705 for (i = 0; i < h; i++) {
706 for (x = 0; x <= w_lim;
707 x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
708 if (x == w_lim) {
709 if ((s = w - w_lim) == 0)
710 break;
711 } else if (!x) {
712 s = (16 - (dst_x % 16));
713 s = MIN(s, w_lim);
714 } else {
715 s = 16;
716 }
717 cmp_bytes = s * depth;
718 if (memcmp(src_row, dst_row, cmp_bytes) == 0)
719 continue;
720 memmove(dst_row, src_row, cmp_bytes);
721 vs = vd->clients;
722 while (vs != NULL) {
723 if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
724 vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16));
725 vs = vs->next;
726 }
727 }
728 src_row += pitch - w * depth;
729 dst_row += pitch - w * depth;
730 y += inc;
731 }
732
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200733 for (vs = vd->clients; vs != NULL; vs = vs->next) {
aliguori753b4052009-02-16 14:59:30 +0000734 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
735 vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
aliguori753b4052009-02-16 14:59:30 +0000736 }
737}
738
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100739static int find_and_clear_dirty_height(struct VncState *vs,
aliguori6baebed2009-03-20 15:59:14 +0000740 int y, int last_x, int x)
bellard24236862006-04-30 21:28:36 +0000741{
742 int h;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100743 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000744
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100745 for (h = 1; h < (vd->server->height - y); h++) {
aliguori28a76be2009-03-06 20:27:40 +0000746 int tmp_x;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100747 if (!vnc_get_bit(vs->dirty[y + h], last_x))
aliguori28a76be2009-03-06 20:27:40 +0000748 break;
749 for (tmp_x = last_x; tmp_x < x; tmp_x++)
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100750 vnc_clear_bit(vs->dirty[y + h], tmp_x);
bellard24236862006-04-30 21:28:36 +0000751 }
752
753 return h;
754}
755
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100756static int vnc_update_client(VncState *vs, int has_dirty)
bellard24236862006-04-30 21:28:36 +0000757{
bellard24236862006-04-30 21:28:36 +0000758 if (vs->need_update && vs->csock != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100759 VncDisplay *vd = vs->vd;
aliguori28a76be2009-03-06 20:27:40 +0000760 int y;
aliguori28a76be2009-03-06 20:27:40 +0000761 int n_rectangles;
762 int saved_offset;
bellard24236862006-04-30 21:28:36 +0000763
Stefano Stabellini703bc682009-08-03 10:54:05 +0100764 if (vs->output.offset && !vs->audio_cap && !vs->force_update)
aliguoric522d0e2009-03-20 15:59:24 +0000765 /* kernel send buffers are full -> drop frames to throttle */
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100766 return 0;
balroga0ecfb72008-01-13 23:51:53 +0000767
Stefano Stabellini703bc682009-08-03 10:54:05 +0100768 if (!has_dirty && !vs->audio_cap && !vs->force_update)
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100769 return 0;
bellard24236862006-04-30 21:28:36 +0000770
aliguori6baebed2009-03-20 15:59:14 +0000771 /*
772 * Send screen updates to the vnc client using the server
773 * surface and server dirty map. guest surface updates
774 * happening in parallel don't disturb us, the next pass will
775 * send them to the client.
776 */
aliguori28a76be2009-03-06 20:27:40 +0000777 n_rectangles = 0;
778 vnc_write_u8(vs, 0); /* msg id */
779 vnc_write_u8(vs, 0);
780 saved_offset = vs->output.offset;
781 vnc_write_u16(vs, 0);
bellard24236862006-04-30 21:28:36 +0000782
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100783 for (y = 0; y < vd->server->height; y++) {
aliguori28a76be2009-03-06 20:27:40 +0000784 int x;
785 int last_x = -1;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100786 for (x = 0; x < vd->server->width / 16; x++) {
787 if (vnc_get_bit(vs->dirty[y], x)) {
aliguori28a76be2009-03-06 20:27:40 +0000788 if (last_x == -1) {
789 last_x = x;
790 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100791 vnc_clear_bit(vs->dirty[y], x);
aliguori28a76be2009-03-06 20:27:40 +0000792 } else {
793 if (last_x != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100794 int h = find_and_clear_dirty_height(vs, y, last_x, x);
aliguori28a76be2009-03-06 20:27:40 +0000795 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
796 n_rectangles++;
797 }
798 last_x = -1;
799 }
800 }
801 if (last_x != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100802 int h = find_and_clear_dirty_height(vs, y, last_x, x);
aliguori28a76be2009-03-06 20:27:40 +0000803 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
804 n_rectangles++;
805 }
806 }
807 vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
808 vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
809 vnc_flush(vs);
aliguoric522d0e2009-03-20 15:59:24 +0000810 vs->force_update = 0;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100811 return n_rectangles;
bellard24236862006-04-30 21:28:36 +0000812 }
bellard24236862006-04-30 21:28:36 +0000813
Stefano Stabellini703bc682009-08-03 10:54:05 +0100814 if (vs->csock == -1)
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200815 vnc_disconnect_finish(vs);
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100816
817 return 0;
bellard24236862006-04-30 21:28:36 +0000818}
819
malc429a8ed2008-12-01 20:57:48 +0000820/* audio */
821static void audio_capture_notify(void *opaque, audcnotification_e cmd)
822{
823 VncState *vs = opaque;
824
825 switch (cmd) {
826 case AUD_CNOTIFY_DISABLE:
827 vnc_write_u8(vs, 255);
828 vnc_write_u8(vs, 1);
829 vnc_write_u16(vs, 0);
830 vnc_flush(vs);
831 break;
832
833 case AUD_CNOTIFY_ENABLE:
834 vnc_write_u8(vs, 255);
835 vnc_write_u8(vs, 1);
836 vnc_write_u16(vs, 1);
837 vnc_flush(vs);
838 break;
839 }
840}
841
842static void audio_capture_destroy(void *opaque)
843{
844}
845
846static void audio_capture(void *opaque, void *buf, int size)
847{
848 VncState *vs = opaque;
849
850 vnc_write_u8(vs, 255);
851 vnc_write_u8(vs, 1);
852 vnc_write_u16(vs, 2);
853 vnc_write_u32(vs, size);
854 vnc_write(vs, buf, size);
855 vnc_flush(vs);
856}
857
858static void audio_add(VncState *vs)
859{
aliguori376253e2009-03-05 23:01:23 +0000860 Monitor *mon = cur_mon;
malc429a8ed2008-12-01 20:57:48 +0000861 struct audio_capture_ops ops;
862
863 if (vs->audio_cap) {
aliguori376253e2009-03-05 23:01:23 +0000864 monitor_printf(mon, "audio already running\n");
malc429a8ed2008-12-01 20:57:48 +0000865 return;
866 }
867
868 ops.notify = audio_capture_notify;
869 ops.destroy = audio_capture_destroy;
870 ops.capture = audio_capture;
871
malc1a7dafc2009-05-14 03:11:35 +0400872 vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
malc429a8ed2008-12-01 20:57:48 +0000873 if (!vs->audio_cap) {
aliguori376253e2009-03-05 23:01:23 +0000874 monitor_printf(mon, "Failed to add audio capture\n");
malc429a8ed2008-12-01 20:57:48 +0000875 }
876}
877
878static void audio_del(VncState *vs)
879{
880 if (vs->audio_cap) {
881 AUD_del_capture(vs->audio_cap, vs);
882 vs->audio_cap = NULL;
883 }
884}
885
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200886static void vnc_disconnect_start(VncState *vs)
887{
888 if (vs->csock == -1)
889 return;
890 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
891 closesocket(vs->csock);
892 vs->csock = -1;
893}
894
895static void vnc_disconnect_finish(VncState *vs)
896{
Stefan Weilfa0cfdf2009-09-19 21:00:09 +0200897 if (vs->input.buffer) {
898 qemu_free(vs->input.buffer);
899 vs->input.buffer = NULL;
900 }
901 if (vs->output.buffer) {
902 qemu_free(vs->output.buffer);
903 vs->output.buffer = NULL;
904 }
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200905#ifdef CONFIG_VNC_TLS
906 vnc_tls_client_cleanup(vs);
907#endif /* CONFIG_VNC_TLS */
908#ifdef CONFIG_VNC_SASL
909 vnc_sasl_client_cleanup(vs);
910#endif /* CONFIG_VNC_SASL */
911 audio_del(vs);
912
913 VncState *p, *parent = NULL;
914 for (p = vs->vd->clients; p != NULL; p = p->next) {
915 if (p == vs) {
916 if (parent)
917 parent->next = p->next;
918 else
919 vs->vd->clients = p->next;
920 break;
921 }
922 parent = p;
923 }
924 if (!vs->vd->clients)
925 dcl->idle = 1;
926
Stefano Stabellini703bc682009-08-03 10:54:05 +0100927 vnc_remove_timer(vs->vd);
Glauber Costa5d95ac52009-09-25 08:30:57 -0400928 qemu_free(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200929}
aliguori2f9606b2009-03-06 20:27:28 +0000930
931int vnc_client_io_error(VncState *vs, int ret, int last_errno)
bellard24236862006-04-30 21:28:36 +0000932{
933 if (ret == 0 || ret == -1) {
balrogea01e5f2008-04-24 23:40:55 +0000934 if (ret == -1) {
935 switch (last_errno) {
936 case EINTR:
937 case EAGAIN:
938#ifdef _WIN32
939 case WSAEWOULDBLOCK:
940#endif
941 return 0;
942 default:
943 break;
944 }
945 }
bellard24236862006-04-30 21:28:36 +0000946
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200947 VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
948 ret, ret < 0 ? last_errno : 0);
949 vnc_disconnect_start(vs);
aliguori6baebed2009-03-20 15:59:14 +0000950
aliguori28a76be2009-03-06 20:27:40 +0000951 return 0;
bellard24236862006-04-30 21:28:36 +0000952 }
953 return ret;
954}
955
aliguori5fb6c7a2009-03-06 20:27:23 +0000956
957void vnc_client_error(VncState *vs)
bellard24236862006-04-30 21:28:36 +0000958{
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200959 VNC_DEBUG("Closing down client sock: protocol error\n");
960 vnc_disconnect_start(vs);
bellard24236862006-04-30 21:28:36 +0000961}
962
aliguori2f9606b2009-03-06 20:27:28 +0000963
964/*
965 * Called to write a chunk of data to the client socket. The data may
966 * be the raw data, or may have already been encoded by SASL.
967 * The data will be written either straight onto the socket, or
968 * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
969 *
970 * NB, it is theoretically possible to have 2 layers of encryption,
971 * both SASL, and this TLS layer. It is highly unlikely in practice
972 * though, since SASL encryption will typically be a no-op if TLS
973 * is active
974 *
975 * Returns the number of bytes written, which may be less than
976 * the requested 'datalen' if the socket would block. Returns
977 * -1 on error, and disconnects the client socket.
978 */
979long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +0000980{
bellardceb5caa2006-05-03 21:18:59 +0000981 long ret;
blueswir1eb38c522008-09-06 17:47:39 +0000982#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +0000983 if (vs->tls.session) {
aliguori28a76be2009-03-06 20:27:40 +0000984 ret = gnutls_write(vs->tls.session, data, datalen);
985 if (ret < 0) {
986 if (ret == GNUTLS_E_AGAIN)
987 errno = EAGAIN;
988 else
989 errno = EIO;
990 ret = -1;
991 }
ths8d5d2d42007-08-25 01:37:51 +0000992 } else
993#endif /* CONFIG_VNC_TLS */
Stefan Weil70503262009-06-13 13:05:27 +0200994 ret = send(vs->csock, (const void *)data, datalen, 0);
aliguori23decc82009-03-20 15:59:18 +0000995 VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +0000996 return vnc_client_io_error(vs, ret, socket_error());
997}
998
999
1000/*
1001 * Called to write buffered data to the client socket, when not
1002 * using any SASL SSF encryption layers. Will write as much data
1003 * as possible without blocking. If all buffered data is written,
1004 * will switch the FD poll() handler back to read monitoring.
1005 *
1006 * Returns the number of bytes written, which may be less than
1007 * the buffered output data if the socket would block. Returns
1008 * -1 on error, and disconnects the client socket.
1009 */
1010static long vnc_client_write_plain(VncState *vs)
1011{
1012 long ret;
1013
1014#ifdef CONFIG_VNC_SASL
aliguori23decc82009-03-20 15:59:18 +00001015 VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
aliguori2f9606b2009-03-06 20:27:28 +00001016 vs->output.buffer, vs->output.capacity, vs->output.offset,
1017 vs->sasl.waitWriteSSF);
1018
1019 if (vs->sasl.conn &&
1020 vs->sasl.runSSF &&
1021 vs->sasl.waitWriteSSF) {
1022 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
1023 if (ret)
1024 vs->sasl.waitWriteSSF -= ret;
1025 } else
1026#endif /* CONFIG_VNC_SASL */
1027 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
bellard24236862006-04-30 21:28:36 +00001028 if (!ret)
aliguori2f9606b2009-03-06 20:27:28 +00001029 return 0;
bellard24236862006-04-30 21:28:36 +00001030
1031 memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
1032 vs->output.offset -= ret;
1033
1034 if (vs->output.offset == 0) {
aliguori28a76be2009-03-06 20:27:40 +00001035 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00001036 }
aliguori2f9606b2009-03-06 20:27:28 +00001037
1038 return ret;
1039}
1040
1041
1042/*
1043 * First function called whenever there is data to be written to
1044 * the client socket. Will delegate actual work according to whether
1045 * SASL SSF layers are enabled (thus requiring encryption calls)
1046 */
1047void vnc_client_write(void *opaque)
1048{
1049 long ret;
1050 VncState *vs = opaque;
1051
1052#ifdef CONFIG_VNC_SASL
1053 if (vs->sasl.conn &&
1054 vs->sasl.runSSF &&
1055 !vs->sasl.waitWriteSSF)
1056 ret = vnc_client_write_sasl(vs);
1057 else
1058#endif /* CONFIG_VNC_SASL */
1059 ret = vnc_client_write_plain(vs);
bellard24236862006-04-30 21:28:36 +00001060}
1061
aliguori5fb6c7a2009-03-06 20:27:23 +00001062void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
bellard24236862006-04-30 21:28:36 +00001063{
1064 vs->read_handler = func;
1065 vs->read_handler_expect = expecting;
1066}
1067
aliguori2f9606b2009-03-06 20:27:28 +00001068
1069/*
1070 * Called to read a chunk of data from the client socket. The data may
1071 * be the raw data, or may need to be further decoded by SASL.
1072 * The data will be read either straight from to the socket, or
1073 * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1074 *
1075 * NB, it is theoretically possible to have 2 layers of encryption,
1076 * both SASL, and this TLS layer. It is highly unlikely in practice
1077 * though, since SASL encryption will typically be a no-op if TLS
1078 * is active
1079 *
1080 * Returns the number of bytes read, which may be less than
1081 * the requested 'datalen' if the socket would block. Returns
1082 * -1 on error, and disconnects the client socket.
1083 */
1084long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001085{
bellardceb5caa2006-05-03 21:18:59 +00001086 long ret;
blueswir1eb38c522008-09-06 17:47:39 +00001087#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +00001088 if (vs->tls.session) {
aliguori28a76be2009-03-06 20:27:40 +00001089 ret = gnutls_read(vs->tls.session, data, datalen);
1090 if (ret < 0) {
1091 if (ret == GNUTLS_E_AGAIN)
1092 errno = EAGAIN;
1093 else
1094 errno = EIO;
1095 ret = -1;
1096 }
ths8d5d2d42007-08-25 01:37:51 +00001097 } else
1098#endif /* CONFIG_VNC_TLS */
Blue Swirlc5b76b32009-06-13 08:44:31 +00001099 ret = recv(vs->csock, (void *)data, datalen, 0);
aliguori23decc82009-03-20 15:59:18 +00001100 VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +00001101 return vnc_client_io_error(vs, ret, socket_error());
1102}
1103
1104
1105/*
1106 * Called to read data from the client socket to the input buffer,
1107 * when not using any SASL SSF encryption layers. Will read as much
1108 * data as possible without blocking.
1109 *
1110 * Returns the number of bytes read. Returns -1 on error, and
1111 * disconnects the client socket.
1112 */
1113static long vnc_client_read_plain(VncState *vs)
1114{
1115 int ret;
aliguori23decc82009-03-20 15:59:18 +00001116 VNC_DEBUG("Read plain %p size %zd offset %zd\n",
aliguori2f9606b2009-03-06 20:27:28 +00001117 vs->input.buffer, vs->input.capacity, vs->input.offset);
1118 buffer_reserve(&vs->input, 4096);
1119 ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
1120 if (!ret)
1121 return 0;
1122 vs->input.offset += ret;
1123 return ret;
1124}
1125
1126
1127/*
1128 * First function called whenever there is more data to be read from
1129 * the client socket. Will delegate actual work according to whether
1130 * SASL SSF layers are enabled (thus requiring decryption calls)
1131 */
1132void vnc_client_read(void *opaque)
1133{
1134 VncState *vs = opaque;
1135 long ret;
1136
1137#ifdef CONFIG_VNC_SASL
1138 if (vs->sasl.conn && vs->sasl.runSSF)
1139 ret = vnc_client_read_sasl(vs);
1140 else
1141#endif /* CONFIG_VNC_SASL */
1142 ret = vnc_client_read_plain(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001143 if (!ret) {
1144 if (vs->csock == -1)
1145 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001146 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001147 }
bellard24236862006-04-30 21:28:36 +00001148
bellard24236862006-04-30 21:28:36 +00001149 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
aliguori28a76be2009-03-06 20:27:40 +00001150 size_t len = vs->read_handler_expect;
1151 int ret;
bellard24236862006-04-30 21:28:36 +00001152
aliguori28a76be2009-03-06 20:27:40 +00001153 ret = vs->read_handler(vs, vs->input.buffer, len);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001154 if (vs->csock == -1) {
1155 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001156 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001157 }
bellard24236862006-04-30 21:28:36 +00001158
aliguori28a76be2009-03-06 20:27:40 +00001159 if (!ret) {
1160 memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
1161 vs->input.offset -= len;
1162 } else {
1163 vs->read_handler_expect = ret;
1164 }
bellard24236862006-04-30 21:28:36 +00001165 }
1166}
1167
aliguori5fb6c7a2009-03-06 20:27:23 +00001168void vnc_write(VncState *vs, const void *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001169{
1170 buffer_reserve(&vs->output, len);
1171
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001172 if (vs->csock != -1 && buffer_empty(&vs->output)) {
aliguori28a76be2009-03-06 20:27:40 +00001173 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
bellard24236862006-04-30 21:28:36 +00001174 }
1175
1176 buffer_append(&vs->output, data, len);
1177}
1178
aliguori5fb6c7a2009-03-06 20:27:23 +00001179void vnc_write_s32(VncState *vs, int32_t value)
bellard24236862006-04-30 21:28:36 +00001180{
1181 vnc_write_u32(vs, *(uint32_t *)&value);
1182}
1183
aliguori5fb6c7a2009-03-06 20:27:23 +00001184void vnc_write_u32(VncState *vs, uint32_t value)
bellard24236862006-04-30 21:28:36 +00001185{
1186 uint8_t buf[4];
1187
1188 buf[0] = (value >> 24) & 0xFF;
1189 buf[1] = (value >> 16) & 0xFF;
1190 buf[2] = (value >> 8) & 0xFF;
1191 buf[3] = value & 0xFF;
1192
1193 vnc_write(vs, buf, 4);
1194}
1195
aliguori5fb6c7a2009-03-06 20:27:23 +00001196void vnc_write_u16(VncState *vs, uint16_t value)
bellard24236862006-04-30 21:28:36 +00001197{
bellard64f5a132006-08-24 20:36:44 +00001198 uint8_t buf[2];
bellard24236862006-04-30 21:28:36 +00001199
1200 buf[0] = (value >> 8) & 0xFF;
1201 buf[1] = value & 0xFF;
1202
1203 vnc_write(vs, buf, 2);
1204}
1205
aliguori5fb6c7a2009-03-06 20:27:23 +00001206void vnc_write_u8(VncState *vs, uint8_t value)
bellard24236862006-04-30 21:28:36 +00001207{
1208 vnc_write(vs, (char *)&value, 1);
1209}
1210
aliguori5fb6c7a2009-03-06 20:27:23 +00001211void vnc_flush(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001212{
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001213 if (vs->csock != -1 && vs->output.offset)
aliguori28a76be2009-03-06 20:27:40 +00001214 vnc_client_write(vs);
bellard24236862006-04-30 21:28:36 +00001215}
1216
aliguori5fb6c7a2009-03-06 20:27:23 +00001217uint8_t read_u8(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001218{
1219 return data[offset];
1220}
1221
aliguori5fb6c7a2009-03-06 20:27:23 +00001222uint16_t read_u16(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001223{
1224 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
1225}
1226
aliguori5fb6c7a2009-03-06 20:27:23 +00001227int32_t read_s32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001228{
1229 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001230 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001231}
1232
aliguori5fb6c7a2009-03-06 20:27:23 +00001233uint32_t read_u32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001234{
1235 return ((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001236 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001237}
1238
ths60fe76f2007-12-16 03:02:09 +00001239static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
bellard24236862006-04-30 21:28:36 +00001240{
1241}
1242
bellard564c3372007-02-05 20:14:10 +00001243static void check_pointer_type_change(VncState *vs, int absolute)
1244{
aliguori29fa4ed2009-02-02 15:58:29 +00001245 if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
aliguori28a76be2009-03-06 20:27:40 +00001246 vnc_write_u8(vs, 0);
1247 vnc_write_u8(vs, 0);
1248 vnc_write_u16(vs, 1);
1249 vnc_framebuffer_update(vs, absolute, 0,
1250 ds_get_width(vs->ds), ds_get_height(vs->ds),
aliguori29fa4ed2009-02-02 15:58:29 +00001251 VNC_ENCODING_POINTER_TYPE_CHANGE);
aliguori28a76be2009-03-06 20:27:40 +00001252 vnc_flush(vs);
bellard564c3372007-02-05 20:14:10 +00001253 }
1254 vs->absolute = absolute;
1255}
1256
bellard24236862006-04-30 21:28:36 +00001257static void pointer_event(VncState *vs, int button_mask, int x, int y)
1258{
1259 int buttons = 0;
1260 int dz = 0;
1261
1262 if (button_mask & 0x01)
aliguori28a76be2009-03-06 20:27:40 +00001263 buttons |= MOUSE_EVENT_LBUTTON;
bellard24236862006-04-30 21:28:36 +00001264 if (button_mask & 0x02)
aliguori28a76be2009-03-06 20:27:40 +00001265 buttons |= MOUSE_EVENT_MBUTTON;
bellard24236862006-04-30 21:28:36 +00001266 if (button_mask & 0x04)
aliguori28a76be2009-03-06 20:27:40 +00001267 buttons |= MOUSE_EVENT_RBUTTON;
bellard24236862006-04-30 21:28:36 +00001268 if (button_mask & 0x08)
aliguori28a76be2009-03-06 20:27:40 +00001269 dz = -1;
bellard24236862006-04-30 21:28:36 +00001270 if (button_mask & 0x10)
aliguori28a76be2009-03-06 20:27:40 +00001271 dz = 1;
bellard564c3372007-02-05 20:14:10 +00001272
1273 if (vs->absolute) {
aliguori28a76be2009-03-06 20:27:40 +00001274 kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
1275 y * 0x7FFF / (ds_get_height(vs->ds) - 1),
1276 dz, buttons);
aliguori29fa4ed2009-02-02 15:58:29 +00001277 } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
aliguori28a76be2009-03-06 20:27:40 +00001278 x -= 0x7FFF;
1279 y -= 0x7FFF;
bellard564c3372007-02-05 20:14:10 +00001280
aliguori28a76be2009-03-06 20:27:40 +00001281 kbd_mouse_event(x, y, dz, buttons);
bellard24236862006-04-30 21:28:36 +00001282 } else {
aliguori28a76be2009-03-06 20:27:40 +00001283 if (vs->last_x != -1)
1284 kbd_mouse_event(x - vs->last_x,
1285 y - vs->last_y,
1286 dz, buttons);
1287 vs->last_x = x;
1288 vs->last_y = y;
bellard24236862006-04-30 21:28:36 +00001289 }
bellard564c3372007-02-05 20:14:10 +00001290
1291 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001292}
1293
bellard64f5a132006-08-24 20:36:44 +00001294static void reset_keys(VncState *vs)
1295{
1296 int i;
1297 for(i = 0; i < 256; i++) {
1298 if (vs->modifiers_state[i]) {
1299 if (i & 0x80)
1300 kbd_put_keycode(0xe0);
1301 kbd_put_keycode(i | 0x80);
1302 vs->modifiers_state[i] = 0;
1303 }
1304 }
1305}
1306
balroga528b802007-10-30 22:38:53 +00001307static void press_key(VncState *vs, int keysym)
1308{
aliguori753b4052009-02-16 14:59:30 +00001309 kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f);
1310 kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80);
balroga528b802007-10-30 22:38:53 +00001311}
1312
aliguori9ca313a2008-08-23 23:27:37 +00001313static void do_key_event(VncState *vs, int down, int keycode, int sym)
bellard24236862006-04-30 21:28:36 +00001314{
bellard64f5a132006-08-24 20:36:44 +00001315 /* QEMU console switch */
1316 switch(keycode) {
1317 case 0x2a: /* Left Shift */
1318 case 0x36: /* Right Shift */
1319 case 0x1d: /* Left CTRL */
1320 case 0x9d: /* Right CTRL */
1321 case 0x38: /* Left ALT */
1322 case 0xb8: /* Right ALT */
1323 if (down)
1324 vs->modifiers_state[keycode] = 1;
1325 else
1326 vs->modifiers_state[keycode] = 0;
1327 break;
ths5fafdf22007-09-16 21:08:06 +00001328 case 0x02 ... 0x0a: /* '1' to '9' keys */
bellard64f5a132006-08-24 20:36:44 +00001329 if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1330 /* Reset the modifiers sent to the current console */
1331 reset_keys(vs);
1332 console_select(keycode - 0x02);
1333 return;
1334 }
1335 break;
aliguori28a76be2009-03-06 20:27:40 +00001336 case 0x3a: /* CapsLock */
1337 case 0x45: /* NumLock */
balroga528b802007-10-30 22:38:53 +00001338 if (!down)
1339 vs->modifiers_state[keycode] ^= 1;
1340 break;
1341 }
1342
aliguori753b4052009-02-16 14:59:30 +00001343 if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
balroga528b802007-10-30 22:38:53 +00001344 /* If the numlock state needs to change then simulate an additional
1345 keypress before sending this one. This will happen if the user
1346 toggles numlock away from the VNC window.
1347 */
aliguori753b4052009-02-16 14:59:30 +00001348 if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
balroga528b802007-10-30 22:38:53 +00001349 if (!vs->modifiers_state[0x45]) {
1350 vs->modifiers_state[0x45] = 1;
1351 press_key(vs, 0xff7f);
1352 }
1353 } else {
1354 if (vs->modifiers_state[0x45]) {
1355 vs->modifiers_state[0x45] = 0;
1356 press_key(vs, 0xff7f);
1357 }
1358 }
bellard64f5a132006-08-24 20:36:44 +00001359 }
bellard24236862006-04-30 21:28:36 +00001360
bellard64f5a132006-08-24 20:36:44 +00001361 if (is_graphic_console()) {
1362 if (keycode & 0x80)
1363 kbd_put_keycode(0xe0);
1364 if (down)
1365 kbd_put_keycode(keycode & 0x7f);
1366 else
1367 kbd_put_keycode(keycode | 0x80);
1368 } else {
1369 /* QEMU console emulation */
1370 if (down) {
Gerd Hoffmannbb0a18e2009-06-11 11:32:14 +02001371 int numlock = vs->modifiers_state[0x45];
bellard64f5a132006-08-24 20:36:44 +00001372 switch (keycode) {
1373 case 0x2a: /* Left Shift */
1374 case 0x36: /* Right Shift */
1375 case 0x1d: /* Left CTRL */
1376 case 0x9d: /* Right CTRL */
1377 case 0x38: /* Left ALT */
1378 case 0xb8: /* Right ALT */
1379 break;
1380 case 0xc8:
1381 kbd_put_keysym(QEMU_KEY_UP);
1382 break;
1383 case 0xd0:
1384 kbd_put_keysym(QEMU_KEY_DOWN);
1385 break;
1386 case 0xcb:
1387 kbd_put_keysym(QEMU_KEY_LEFT);
1388 break;
1389 case 0xcd:
1390 kbd_put_keysym(QEMU_KEY_RIGHT);
1391 break;
1392 case 0xd3:
1393 kbd_put_keysym(QEMU_KEY_DELETE);
1394 break;
1395 case 0xc7:
1396 kbd_put_keysym(QEMU_KEY_HOME);
1397 break;
1398 case 0xcf:
1399 kbd_put_keysym(QEMU_KEY_END);
1400 break;
1401 case 0xc9:
1402 kbd_put_keysym(QEMU_KEY_PAGEUP);
1403 break;
1404 case 0xd1:
1405 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1406 break;
Gerd Hoffmannbb0a18e2009-06-11 11:32:14 +02001407
1408 case 0x47:
1409 kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
1410 break;
1411 case 0x48:
1412 kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
1413 break;
1414 case 0x49:
1415 kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
1416 break;
1417 case 0x4b:
1418 kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
1419 break;
1420 case 0x4c:
1421 kbd_put_keysym('5');
1422 break;
1423 case 0x4d:
1424 kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
1425 break;
1426 case 0x4f:
1427 kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
1428 break;
1429 case 0x50:
1430 kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
1431 break;
1432 case 0x51:
1433 kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
1434 break;
1435 case 0x52:
1436 kbd_put_keysym('0');
1437 break;
1438 case 0x53:
1439 kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
1440 break;
1441
1442 case 0xb5:
1443 kbd_put_keysym('/');
1444 break;
1445 case 0x37:
1446 kbd_put_keysym('*');
1447 break;
1448 case 0x4a:
1449 kbd_put_keysym('-');
1450 break;
1451 case 0x4e:
1452 kbd_put_keysym('+');
1453 break;
1454 case 0x9c:
1455 kbd_put_keysym('\n');
1456 break;
1457
bellard64f5a132006-08-24 20:36:44 +00001458 default:
1459 kbd_put_keysym(sym);
1460 break;
1461 }
1462 }
1463 }
bellard24236862006-04-30 21:28:36 +00001464}
1465
bellardbdbd7672006-05-01 21:44:22 +00001466static void key_event(VncState *vs, int down, uint32_t sym)
1467{
aliguori9ca313a2008-08-23 23:27:37 +00001468 int keycode;
1469
balroga528b802007-10-30 22:38:53 +00001470 if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
aliguori28a76be2009-03-06 20:27:40 +00001471 sym = sym - 'A' + 'a';
aliguori9ca313a2008-08-23 23:27:37 +00001472
aliguori753b4052009-02-16 14:59:30 +00001473 keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF);
aliguori9ca313a2008-08-23 23:27:37 +00001474 do_key_event(vs, down, keycode, sym);
1475}
1476
1477static void ext_key_event(VncState *vs, int down,
1478 uint32_t sym, uint16_t keycode)
1479{
1480 /* if the user specifies a keyboard layout, always use it */
1481 if (keyboard_layout)
1482 key_event(vs, down, sym);
1483 else
1484 do_key_event(vs, down, keycode, sym);
bellardbdbd7672006-05-01 21:44:22 +00001485}
1486
bellard24236862006-04-30 21:28:36 +00001487static void framebuffer_update_request(VncState *vs, int incremental,
aliguori28a76be2009-03-06 20:27:40 +00001488 int x_position, int y_position,
1489 int w, int h)
bellard24236862006-04-30 21:28:36 +00001490{
aliguori0e1f5a02008-11-24 19:29:13 +00001491 if (x_position > ds_get_width(vs->ds))
1492 x_position = ds_get_width(vs->ds);
1493 if (y_position > ds_get_height(vs->ds))
1494 y_position = ds_get_height(vs->ds);
1495 if (x_position + w >= ds_get_width(vs->ds))
1496 w = ds_get_width(vs->ds) - x_position;
1497 if (y_position + h >= ds_get_height(vs->ds))
1498 h = ds_get_height(vs->ds) - y_position;
thscf2d3852007-04-29 01:53:20 +00001499
bellard24236862006-04-30 21:28:36 +00001500 int i;
1501 vs->need_update = 1;
1502 if (!incremental) {
Gerd Hoffmann24cf0a62009-04-27 16:39:52 +02001503 vs->force_update = 1;
aliguori28a76be2009-03-06 20:27:40 +00001504 for (i = 0; i < h; i++) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +01001505 vnc_set_bits(vs->dirty[y_position + i],
aliguori6baebed2009-03-20 15:59:14 +00001506 (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
aliguori28a76be2009-03-06 20:27:40 +00001507 }
bellard24236862006-04-30 21:28:36 +00001508 }
1509}
1510
aliguori9ca313a2008-08-23 23:27:37 +00001511static void send_ext_key_event_ack(VncState *vs)
1512{
1513 vnc_write_u8(vs, 0);
1514 vnc_write_u8(vs, 0);
1515 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001516 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1517 VNC_ENCODING_EXT_KEY_EVENT);
aliguori9ca313a2008-08-23 23:27:37 +00001518 vnc_flush(vs);
1519}
1520
malc429a8ed2008-12-01 20:57:48 +00001521static void send_ext_audio_ack(VncState *vs)
1522{
1523 vnc_write_u8(vs, 0);
1524 vnc_write_u8(vs, 0);
1525 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001526 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1527 VNC_ENCODING_AUDIO);
malc429a8ed2008-12-01 20:57:48 +00001528 vnc_flush(vs);
1529}
1530
bellard24236862006-04-30 21:28:36 +00001531static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1532{
1533 int i;
aliguori29fa4ed2009-02-02 15:58:29 +00001534 unsigned int enc = 0;
bellard24236862006-04-30 21:28:36 +00001535
aliguori059cef42009-02-02 15:58:54 +00001536 vnc_zlib_init(vs);
aliguori29fa4ed2009-02-02 15:58:29 +00001537 vs->features = 0;
aliguorifb437312009-02-02 15:58:43 +00001538 vs->vnc_encoding = 0;
1539 vs->tight_compression = 9;
1540 vs->tight_quality = 9;
bellard564c3372007-02-05 20:14:10 +00001541 vs->absolute = -1;
bellard24236862006-04-30 21:28:36 +00001542
1543 for (i = n_encodings - 1; i >= 0; i--) {
aliguori29fa4ed2009-02-02 15:58:29 +00001544 enc = encodings[i];
1545 switch (enc) {
1546 case VNC_ENCODING_RAW:
aliguorifb437312009-02-02 15:58:43 +00001547 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001548 break;
1549 case VNC_ENCODING_COPYRECT:
aliguori753b4052009-02-16 14:59:30 +00001550 vs->features |= VNC_FEATURE_COPYRECT_MASK;
aliguori29fa4ed2009-02-02 15:58:29 +00001551 break;
1552 case VNC_ENCODING_HEXTILE:
1553 vs->features |= VNC_FEATURE_HEXTILE_MASK;
aliguorifb437312009-02-02 15:58:43 +00001554 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001555 break;
aliguori059cef42009-02-02 15:58:54 +00001556 case VNC_ENCODING_ZLIB:
1557 vs->features |= VNC_FEATURE_ZLIB_MASK;
1558 vs->vnc_encoding = enc;
1559 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001560 case VNC_ENCODING_DESKTOPRESIZE:
1561 vs->features |= VNC_FEATURE_RESIZE_MASK;
1562 break;
1563 case VNC_ENCODING_POINTER_TYPE_CHANGE:
1564 vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
1565 break;
1566 case VNC_ENCODING_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00001567 send_ext_key_event_ack(vs);
1568 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001569 case VNC_ENCODING_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00001570 send_ext_audio_ack(vs);
1571 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001572 case VNC_ENCODING_WMVi:
1573 vs->features |= VNC_FEATURE_WMVI_MASK;
aliguorica4cca42008-09-15 16:05:16 +00001574 break;
aliguorifb437312009-02-02 15:58:43 +00001575 case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
1576 vs->tight_compression = (enc & 0x0F);
1577 break;
1578 case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
1579 vs->tight_quality = (enc & 0x0F);
1580 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001581 default:
1582 VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
1583 break;
1584 }
bellard24236862006-04-30 21:28:36 +00001585 }
bellard564c3372007-02-05 20:14:10 +00001586
1587 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001588}
1589
aliguori6cec5482009-01-15 22:17:38 +00001590static void set_pixel_conversion(VncState *vs)
1591{
1592 if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
1593 (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) &&
1594 !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
1595 vs->write_pixels = vnc_write_pixels_copy;
1596 switch (vs->ds->surface->pf.bits_per_pixel) {
1597 case 8:
1598 vs->send_hextile_tile = send_hextile_tile_8;
1599 break;
1600 case 16:
1601 vs->send_hextile_tile = send_hextile_tile_16;
1602 break;
1603 case 32:
1604 vs->send_hextile_tile = send_hextile_tile_32;
1605 break;
1606 }
1607 } else {
1608 vs->write_pixels = vnc_write_pixels_generic;
1609 switch (vs->ds->surface->pf.bits_per_pixel) {
1610 case 8:
1611 vs->send_hextile_tile = send_hextile_tile_generic_8;
1612 break;
1613 case 16:
1614 vs->send_hextile_tile = send_hextile_tile_generic_16;
1615 break;
1616 case 32:
1617 vs->send_hextile_tile = send_hextile_tile_generic_32;
1618 break;
1619 }
1620 }
1621}
1622
bellard24236862006-04-30 21:28:36 +00001623static void set_pixel_format(VncState *vs,
aliguori28a76be2009-03-06 20:27:40 +00001624 int bits_per_pixel, int depth,
1625 int big_endian_flag, int true_color_flag,
1626 int red_max, int green_max, int blue_max,
1627 int red_shift, int green_shift, int blue_shift)
bellard24236862006-04-30 21:28:36 +00001628{
bellard35127792006-05-14 18:11:49 +00001629 if (!true_color_flag) {
aliguori28a76be2009-03-06 20:27:40 +00001630 vnc_client_error(vs);
bellard35127792006-05-14 18:11:49 +00001631 return;
1632 }
aliguori7eac3a82008-09-15 16:03:41 +00001633
Stefano Stabellini1fc62412009-08-03 10:54:32 +01001634 vs->clientds = *(vs->vd->guest.ds);
aliguori6cec5482009-01-15 22:17:38 +00001635 vs->clientds.pf.rmax = red_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001636 count_bits(vs->clientds.pf.rbits, red_max);
aliguori6cec5482009-01-15 22:17:38 +00001637 vs->clientds.pf.rshift = red_shift;
1638 vs->clientds.pf.rmask = red_max << red_shift;
1639 vs->clientds.pf.gmax = green_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001640 count_bits(vs->clientds.pf.gbits, green_max);
aliguori6cec5482009-01-15 22:17:38 +00001641 vs->clientds.pf.gshift = green_shift;
1642 vs->clientds.pf.gmask = green_max << green_shift;
1643 vs->clientds.pf.bmax = blue_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001644 count_bits(vs->clientds.pf.bbits, blue_max);
aliguori6cec5482009-01-15 22:17:38 +00001645 vs->clientds.pf.bshift = blue_shift;
1646 vs->clientds.pf.bmask = blue_max << blue_shift;
1647 vs->clientds.pf.bits_per_pixel = bits_per_pixel;
1648 vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
1649 vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
1650 vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
bellard24236862006-04-30 21:28:36 +00001651
aliguori6cec5482009-01-15 22:17:38 +00001652 set_pixel_conversion(vs);
bellard24236862006-04-30 21:28:36 +00001653
1654 vga_hw_invalidate();
1655 vga_hw_update();
1656}
1657
aliguorica4cca42008-09-15 16:05:16 +00001658static void pixel_format_message (VncState *vs) {
1659 char pad[3] = { 0, 0, 0 };
1660
aliguori6cec5482009-01-15 22:17:38 +00001661 vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
1662 vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
aliguorica4cca42008-09-15 16:05:16 +00001663
Juan Quintelae2542fe2009-07-27 16:13:06 +02001664#ifdef HOST_WORDS_BIGENDIAN
aliguorica4cca42008-09-15 16:05:16 +00001665 vnc_write_u8(vs, 1); /* big-endian-flag */
1666#else
1667 vnc_write_u8(vs, 0); /* big-endian-flag */
1668#endif
1669 vnc_write_u8(vs, 1); /* true-color-flag */
aliguori6cec5482009-01-15 22:17:38 +00001670 vnc_write_u16(vs, vs->ds->surface->pf.rmax); /* red-max */
1671 vnc_write_u16(vs, vs->ds->surface->pf.gmax); /* green-max */
1672 vnc_write_u16(vs, vs->ds->surface->pf.bmax); /* blue-max */
1673 vnc_write_u8(vs, vs->ds->surface->pf.rshift); /* red-shift */
1674 vnc_write_u8(vs, vs->ds->surface->pf.gshift); /* green-shift */
1675 vnc_write_u8(vs, vs->ds->surface->pf.bshift); /* blue-shift */
1676 if (vs->ds->surface->pf.bits_per_pixel == 32)
aliguorica4cca42008-09-15 16:05:16 +00001677 vs->send_hextile_tile = send_hextile_tile_32;
aliguori6cec5482009-01-15 22:17:38 +00001678 else if (vs->ds->surface->pf.bits_per_pixel == 16)
aliguorica4cca42008-09-15 16:05:16 +00001679 vs->send_hextile_tile = send_hextile_tile_16;
aliguori6cec5482009-01-15 22:17:38 +00001680 else if (vs->ds->surface->pf.bits_per_pixel == 8)
aliguorica4cca42008-09-15 16:05:16 +00001681 vs->send_hextile_tile = send_hextile_tile_8;
aliguori6cec5482009-01-15 22:17:38 +00001682 vs->clientds = *(vs->ds->surface);
aurel323cded542009-04-07 19:57:09 +00001683 vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
aliguorica4cca42008-09-15 16:05:16 +00001684 vs->write_pixels = vnc_write_pixels_copy;
1685
1686 vnc_write(vs, pad, 3); /* padding */
1687}
1688
aliguori7d957bd2009-01-15 22:14:11 +00001689static void vnc_dpy_setdata(DisplayState *ds)
1690{
1691 /* We don't have to do anything */
1692}
1693
aliguori753b4052009-02-16 14:59:30 +00001694static void vnc_colordepth(VncState *vs)
aliguori7eac3a82008-09-15 16:03:41 +00001695{
aliguori753b4052009-02-16 14:59:30 +00001696 if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
aliguorica4cca42008-09-15 16:05:16 +00001697 /* Sending a WMVi message to notify the client*/
1698 vnc_write_u8(vs, 0); /* msg id */
1699 vnc_write_u8(vs, 0);
1700 vnc_write_u16(vs, 1); /* number of rects */
aliguori753b4052009-02-16 14:59:30 +00001701 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds),
1702 ds_get_height(vs->ds), VNC_ENCODING_WMVi);
aliguorica4cca42008-09-15 16:05:16 +00001703 pixel_format_message(vs);
1704 vnc_flush(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001705 } else {
aliguori6cec5482009-01-15 22:17:38 +00001706 set_pixel_conversion(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001707 }
1708}
1709
ths60fe76f2007-12-16 03:02:09 +00001710static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001711{
1712 int i;
1713 uint16_t limit;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01001714 VncDisplay *vd = vs->vd;
1715
1716 if (data[0] > 3) {
1717 vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
1718 if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval))
1719 qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
1720 }
bellard24236862006-04-30 21:28:36 +00001721
1722 switch (data[0]) {
1723 case 0:
aliguori28a76be2009-03-06 20:27:40 +00001724 if (len == 1)
1725 return 20;
bellard24236862006-04-30 21:28:36 +00001726
aliguori28a76be2009-03-06 20:27:40 +00001727 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
1728 read_u8(data, 6), read_u8(data, 7),
1729 read_u16(data, 8), read_u16(data, 10),
1730 read_u16(data, 12), read_u8(data, 14),
1731 read_u8(data, 15), read_u8(data, 16));
1732 break;
bellard24236862006-04-30 21:28:36 +00001733 case 2:
aliguori28a76be2009-03-06 20:27:40 +00001734 if (len == 1)
1735 return 4;
bellard24236862006-04-30 21:28:36 +00001736
aliguori28a76be2009-03-06 20:27:40 +00001737 if (len == 4) {
aliguori69dd5c92008-12-22 21:06:23 +00001738 limit = read_u16(data, 2);
1739 if (limit > 0)
1740 return 4 + (limit * 4);
1741 } else
1742 limit = read_u16(data, 2);
bellard24236862006-04-30 21:28:36 +00001743
aliguori28a76be2009-03-06 20:27:40 +00001744 for (i = 0; i < limit; i++) {
1745 int32_t val = read_s32(data, 4 + (i * 4));
1746 memcpy(data + 4 + (i * 4), &val, sizeof(val));
1747 }
bellard24236862006-04-30 21:28:36 +00001748
aliguori28a76be2009-03-06 20:27:40 +00001749 set_encodings(vs, (int32_t *)(data + 4), limit);
1750 break;
bellard24236862006-04-30 21:28:36 +00001751 case 3:
aliguori28a76be2009-03-06 20:27:40 +00001752 if (len == 1)
1753 return 10;
bellard24236862006-04-30 21:28:36 +00001754
aliguori28a76be2009-03-06 20:27:40 +00001755 framebuffer_update_request(vs,
1756 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
1757 read_u16(data, 6), read_u16(data, 8));
1758 break;
bellard24236862006-04-30 21:28:36 +00001759 case 4:
aliguori28a76be2009-03-06 20:27:40 +00001760 if (len == 1)
1761 return 8;
bellard24236862006-04-30 21:28:36 +00001762
aliguori28a76be2009-03-06 20:27:40 +00001763 key_event(vs, read_u8(data, 1), read_u32(data, 4));
1764 break;
bellard24236862006-04-30 21:28:36 +00001765 case 5:
aliguori28a76be2009-03-06 20:27:40 +00001766 if (len == 1)
1767 return 6;
bellard24236862006-04-30 21:28:36 +00001768
aliguori28a76be2009-03-06 20:27:40 +00001769 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
1770 break;
bellard24236862006-04-30 21:28:36 +00001771 case 6:
aliguori28a76be2009-03-06 20:27:40 +00001772 if (len == 1)
1773 return 8;
bellard24236862006-04-30 21:28:36 +00001774
aliguori28a76be2009-03-06 20:27:40 +00001775 if (len == 8) {
thsbaa76662007-09-13 12:41:42 +00001776 uint32_t dlen = read_u32(data, 4);
1777 if (dlen > 0)
1778 return 8 + dlen;
1779 }
bellard24236862006-04-30 21:28:36 +00001780
aliguori28a76be2009-03-06 20:27:40 +00001781 client_cut_text(vs, read_u32(data, 4), data + 8);
1782 break;
aliguori9ca313a2008-08-23 23:27:37 +00001783 case 255:
1784 if (len == 1)
1785 return 2;
1786
1787 switch (read_u8(data, 1)) {
1788 case 0:
1789 if (len == 2)
1790 return 12;
1791
1792 ext_key_event(vs, read_u16(data, 2),
1793 read_u32(data, 4), read_u32(data, 8));
1794 break;
malc429a8ed2008-12-01 20:57:48 +00001795 case 1:
1796 if (len == 2)
1797 return 4;
1798
1799 switch (read_u16 (data, 2)) {
1800 case 0:
1801 audio_add(vs);
1802 break;
1803 case 1:
1804 audio_del(vs);
1805 break;
1806 case 2:
1807 if (len == 4)
1808 return 10;
1809 switch (read_u8(data, 4)) {
1810 case 0: vs->as.fmt = AUD_FMT_U8; break;
1811 case 1: vs->as.fmt = AUD_FMT_S8; break;
1812 case 2: vs->as.fmt = AUD_FMT_U16; break;
1813 case 3: vs->as.fmt = AUD_FMT_S16; break;
1814 case 4: vs->as.fmt = AUD_FMT_U32; break;
1815 case 5: vs->as.fmt = AUD_FMT_S32; break;
1816 default:
1817 printf("Invalid audio format %d\n", read_u8(data, 4));
1818 vnc_client_error(vs);
1819 break;
1820 }
1821 vs->as.nchannels = read_u8(data, 5);
1822 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
1823 printf("Invalid audio channel coount %d\n",
1824 read_u8(data, 5));
1825 vnc_client_error(vs);
1826 break;
1827 }
1828 vs->as.freq = read_u32(data, 6);
1829 break;
1830 default:
1831 printf ("Invalid audio message %d\n", read_u8(data, 4));
1832 vnc_client_error(vs);
1833 break;
1834 }
1835 break;
1836
aliguori9ca313a2008-08-23 23:27:37 +00001837 default:
1838 printf("Msg: %d\n", read_u16(data, 0));
1839 vnc_client_error(vs);
1840 break;
1841 }
1842 break;
bellard24236862006-04-30 21:28:36 +00001843 default:
aliguori28a76be2009-03-06 20:27:40 +00001844 printf("Msg: %d\n", data[0]);
1845 vnc_client_error(vs);
1846 break;
bellard24236862006-04-30 21:28:36 +00001847 }
ths5fafdf22007-09-16 21:08:06 +00001848
bellard24236862006-04-30 21:28:36 +00001849 vnc_read_when(vs, protocol_client_msg, 1);
1850 return 0;
1851}
1852
ths60fe76f2007-12-16 03:02:09 +00001853static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001854{
thsc35734b2007-03-19 15:17:08 +00001855 char buf[1024];
1856 int size;
bellard24236862006-04-30 21:28:36 +00001857
aliguori0e1f5a02008-11-24 19:29:13 +00001858 vnc_write_u16(vs, ds_get_width(vs->ds));
1859 vnc_write_u16(vs, ds_get_height(vs->ds));
bellard24236862006-04-30 21:28:36 +00001860
aliguorica4cca42008-09-15 16:05:16 +00001861 pixel_format_message(vs);
bellard24236862006-04-30 21:28:36 +00001862
thsc35734b2007-03-19 15:17:08 +00001863 if (qemu_name)
1864 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
1865 else
1866 size = snprintf(buf, sizeof(buf), "QEMU");
1867
1868 vnc_write_u32(vs, size);
1869 vnc_write(vs, buf, size);
bellard24236862006-04-30 21:28:36 +00001870 vnc_flush(vs);
1871
1872 vnc_read_when(vs, protocol_client_msg, 1);
1873
1874 return 0;
1875}
1876
aliguori5fb6c7a2009-03-06 20:27:23 +00001877void start_client_init(VncState *vs)
1878{
1879 vnc_read_when(vs, protocol_client_init, 1);
1880}
1881
ths70848512007-08-25 01:37:05 +00001882static void make_challenge(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001883{
ths70848512007-08-25 01:37:05 +00001884 int i;
bellard24236862006-04-30 21:28:36 +00001885
ths70848512007-08-25 01:37:05 +00001886 srand(time(NULL)+getpid()+getpid()*987654+rand());
bellard24236862006-04-30 21:28:36 +00001887
ths70848512007-08-25 01:37:05 +00001888 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
1889 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
1890}
1891
ths60fe76f2007-12-16 03:02:09 +00001892static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00001893{
ths60fe76f2007-12-16 03:02:09 +00001894 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
ths70848512007-08-25 01:37:05 +00001895 int i, j, pwlen;
ths60fe76f2007-12-16 03:02:09 +00001896 unsigned char key[8];
ths70848512007-08-25 01:37:05 +00001897
aliguori753b4052009-02-16 14:59:30 +00001898 if (!vs->vd->password || !vs->vd->password[0]) {
aliguori28a76be2009-03-06 20:27:40 +00001899 VNC_DEBUG("No password configured on server");
1900 vnc_write_u32(vs, 1); /* Reject auth */
1901 if (vs->minor >= 8) {
1902 static const char err[] = "Authentication failed";
1903 vnc_write_u32(vs, sizeof(err));
1904 vnc_write(vs, err, sizeof(err));
1905 }
1906 vnc_flush(vs);
1907 vnc_client_error(vs);
1908 return 0;
bellard24236862006-04-30 21:28:36 +00001909 }
1910
ths70848512007-08-25 01:37:05 +00001911 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
1912
1913 /* Calculate the expected challenge response */
aliguori753b4052009-02-16 14:59:30 +00001914 pwlen = strlen(vs->vd->password);
ths70848512007-08-25 01:37:05 +00001915 for (i=0; i<sizeof(key); i++)
aliguori753b4052009-02-16 14:59:30 +00001916 key[i] = i<pwlen ? vs->vd->password[i] : 0;
ths70848512007-08-25 01:37:05 +00001917 deskey(key, EN0);
1918 for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
1919 des(response+j, response+j);
1920
1921 /* Compare expected vs actual challenge response */
1922 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
aliguori28a76be2009-03-06 20:27:40 +00001923 VNC_DEBUG("Client challenge reponse did not match\n");
1924 vnc_write_u32(vs, 1); /* Reject auth */
1925 if (vs->minor >= 8) {
1926 static const char err[] = "Authentication failed";
1927 vnc_write_u32(vs, sizeof(err));
1928 vnc_write(vs, err, sizeof(err));
1929 }
1930 vnc_flush(vs);
1931 vnc_client_error(vs);
ths70848512007-08-25 01:37:05 +00001932 } else {
aliguori28a76be2009-03-06 20:27:40 +00001933 VNC_DEBUG("Accepting VNC challenge response\n");
1934 vnc_write_u32(vs, 0); /* Accept auth */
1935 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00001936
aliguori5fb6c7a2009-03-06 20:27:23 +00001937 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00001938 }
1939 return 0;
1940}
1941
aliguori5fb6c7a2009-03-06 20:27:23 +00001942void start_auth_vnc(VncState *vs)
ths70848512007-08-25 01:37:05 +00001943{
1944 make_challenge(vs);
1945 /* Send client a 'random' challenge */
1946 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
bellard24236862006-04-30 21:28:36 +00001947 vnc_flush(vs);
1948
ths70848512007-08-25 01:37:05 +00001949 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
ths70848512007-08-25 01:37:05 +00001950}
1951
ths8d5d2d42007-08-25 01:37:51 +00001952
ths60fe76f2007-12-16 03:02:09 +00001953static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00001954{
1955 /* We only advertise 1 auth scheme at a time, so client
1956 * must pick the one we sent. Verify this */
aliguori753b4052009-02-16 14:59:30 +00001957 if (data[0] != vs->vd->auth) { /* Reject auth */
aliguori1263b7d2009-03-06 20:27:32 +00001958 VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
ths70848512007-08-25 01:37:05 +00001959 vnc_write_u32(vs, 1);
1960 if (vs->minor >= 8) {
1961 static const char err[] = "Authentication failed";
1962 vnc_write_u32(vs, sizeof(err));
1963 vnc_write(vs, err, sizeof(err));
1964 }
1965 vnc_client_error(vs);
1966 } else { /* Accept requested auth */
1967 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
aliguori753b4052009-02-16 14:59:30 +00001968 switch (vs->vd->auth) {
ths70848512007-08-25 01:37:05 +00001969 case VNC_AUTH_NONE:
1970 VNC_DEBUG("Accept auth none\n");
balroga26c97a2007-10-31 01:58:56 +00001971 if (vs->minor >= 8) {
1972 vnc_write_u32(vs, 0); /* Accept auth completion */
1973 vnc_flush(vs);
1974 }
aliguori5fb6c7a2009-03-06 20:27:23 +00001975 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00001976 break;
1977
1978 case VNC_AUTH_VNC:
1979 VNC_DEBUG("Start VNC auth\n");
aliguori5fb6c7a2009-03-06 20:27:23 +00001980 start_auth_vnc(vs);
1981 break;
ths70848512007-08-25 01:37:05 +00001982
blueswir1eb38c522008-09-06 17:47:39 +00001983#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00001984 case VNC_AUTH_VENCRYPT:
1985 VNC_DEBUG("Accept VeNCrypt auth\n");;
aliguori5fb6c7a2009-03-06 20:27:23 +00001986 start_auth_vencrypt(vs);
1987 break;
ths8d5d2d42007-08-25 01:37:51 +00001988#endif /* CONFIG_VNC_TLS */
1989
aliguori2f9606b2009-03-06 20:27:28 +00001990#ifdef CONFIG_VNC_SASL
1991 case VNC_AUTH_SASL:
1992 VNC_DEBUG("Accept SASL auth\n");
1993 start_auth_sasl(vs);
1994 break;
1995#endif /* CONFIG_VNC_SASL */
1996
ths70848512007-08-25 01:37:05 +00001997 default: /* Should not be possible, but just in case */
aliguori1263b7d2009-03-06 20:27:32 +00001998 VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
ths70848512007-08-25 01:37:05 +00001999 vnc_write_u8(vs, 1);
2000 if (vs->minor >= 8) {
2001 static const char err[] = "Authentication failed";
2002 vnc_write_u32(vs, sizeof(err));
2003 vnc_write(vs, err, sizeof(err));
2004 }
2005 vnc_client_error(vs);
2006 }
2007 }
2008 return 0;
2009}
2010
ths60fe76f2007-12-16 03:02:09 +00002011static int protocol_version(VncState *vs, uint8_t *version, size_t len)
ths70848512007-08-25 01:37:05 +00002012{
2013 char local[13];
2014
2015 memcpy(local, version, 12);
2016 local[12] = 0;
2017
2018 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
aliguori28a76be2009-03-06 20:27:40 +00002019 VNC_DEBUG("Malformed protocol version %s\n", local);
2020 vnc_client_error(vs);
2021 return 0;
ths70848512007-08-25 01:37:05 +00002022 }
2023 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2024 if (vs->major != 3 ||
aliguori28a76be2009-03-06 20:27:40 +00002025 (vs->minor != 3 &&
2026 vs->minor != 4 &&
2027 vs->minor != 5 &&
2028 vs->minor != 7 &&
2029 vs->minor != 8)) {
2030 VNC_DEBUG("Unsupported client version\n");
2031 vnc_write_u32(vs, VNC_AUTH_INVALID);
2032 vnc_flush(vs);
2033 vnc_client_error(vs);
2034 return 0;
ths70848512007-08-25 01:37:05 +00002035 }
thsb0566f42007-09-30 13:01:15 +00002036 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
ths70848512007-08-25 01:37:05 +00002037 * as equivalent to v3.3 by servers
2038 */
thsb0566f42007-09-30 13:01:15 +00002039 if (vs->minor == 4 || vs->minor == 5)
aliguori28a76be2009-03-06 20:27:40 +00002040 vs->minor = 3;
ths70848512007-08-25 01:37:05 +00002041
2042 if (vs->minor == 3) {
aliguori28a76be2009-03-06 20:27:40 +00002043 if (vs->vd->auth == VNC_AUTH_NONE) {
ths70848512007-08-25 01:37:05 +00002044 VNC_DEBUG("Tell client auth none\n");
aliguori753b4052009-02-16 14:59:30 +00002045 vnc_write_u32(vs, vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002046 vnc_flush(vs);
aliguori28a76be2009-03-06 20:27:40 +00002047 start_client_init(vs);
aliguori753b4052009-02-16 14:59:30 +00002048 } else if (vs->vd->auth == VNC_AUTH_VNC) {
ths70848512007-08-25 01:37:05 +00002049 VNC_DEBUG("Tell client VNC auth\n");
aliguori753b4052009-02-16 14:59:30 +00002050 vnc_write_u32(vs, vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002051 vnc_flush(vs);
2052 start_auth_vnc(vs);
2053 } else {
aliguori753b4052009-02-16 14:59:30 +00002054 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002055 vnc_write_u32(vs, VNC_AUTH_INVALID);
2056 vnc_flush(vs);
2057 vnc_client_error(vs);
2058 }
2059 } else {
aliguori28a76be2009-03-06 20:27:40 +00002060 VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
2061 vnc_write_u8(vs, 1); /* num auth */
2062 vnc_write_u8(vs, vs->vd->auth);
2063 vnc_read_when(vs, protocol_client_auth, 1);
2064 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002065 }
bellard24236862006-04-30 21:28:36 +00002066
2067 return 0;
2068}
2069
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002070static int vnc_refresh_server_surface(VncDisplay *vd)
2071{
2072 int y;
2073 uint8_t *guest_row;
2074 uint8_t *server_row;
2075 int cmp_bytes;
2076 uint32_t width_mask[VNC_DIRTY_WORDS];
2077 VncState *vs = NULL;
2078 int has_dirty = 0;
2079
2080 /*
2081 * Walk through the guest dirty map.
2082 * Check and copy modified bits from guest to server surface.
2083 * Update server dirty map.
2084 */
2085 vnc_set_bits(width_mask, (ds_get_width(vd->ds) / 16), VNC_DIRTY_WORDS);
2086 cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
2087 guest_row = vd->guest.ds->data;
2088 server_row = vd->server->data;
2089 for (y = 0; y < vd->guest.ds->height; y++) {
2090 if (vnc_and_bits(vd->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
2091 int x;
2092 uint8_t *guest_ptr;
2093 uint8_t *server_ptr;
2094
2095 guest_ptr = guest_row;
2096 server_ptr = server_row;
2097
2098 for (x = 0; x < vd->guest.ds->width;
2099 x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
2100 if (!vnc_get_bit(vd->guest.dirty[y], (x / 16)))
2101 continue;
2102 vnc_clear_bit(vd->guest.dirty[y], (x / 16));
2103 if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
2104 continue;
2105 memcpy(server_ptr, guest_ptr, cmp_bytes);
2106 vs = vd->clients;
2107 while (vs != NULL) {
2108 vnc_set_bit(vs->dirty[y], (x / 16));
2109 vs = vs->next;
2110 }
2111 has_dirty++;
2112 }
2113 }
2114 guest_row += ds_get_linesize(vd->ds);
2115 server_row += ds_get_linesize(vd->ds);
2116 }
2117 return has_dirty;
2118}
2119
Stefano Stabellini703bc682009-08-03 10:54:05 +01002120static void vnc_refresh(void *opaque)
2121{
2122 VncDisplay *vd = opaque;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002123 VncState *vs = NULL;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002124 int has_dirty = 0, rects = 0;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002125
2126 vga_hw_update();
2127
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002128 has_dirty = vnc_refresh_server_surface(vd);
2129
2130 vs = vd->clients;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002131 while (vs != NULL) {
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002132 rects += vnc_update_client(vs, has_dirty);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002133 vs = vs->next;
2134 }
2135
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002136 if (has_dirty && rects) {
2137 vd->timer_interval /= 2;
2138 if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE)
2139 vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
2140 } else {
2141 vd->timer_interval += VNC_REFRESH_INTERVAL_INC;
2142 if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
2143 vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
2144 }
2145 qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002146}
2147
2148static void vnc_init_timer(VncDisplay *vd)
2149{
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002150 vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002151 if (vd->timer == NULL && vd->clients != NULL) {
2152 vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002153 vnc_refresh(vd);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002154 }
2155}
2156
2157static void vnc_remove_timer(VncDisplay *vd)
2158{
2159 if (vd->timer != NULL && vd->clients == NULL) {
2160 qemu_del_timer(vd->timer);
2161 qemu_free_timer(vd->timer);
2162 vd->timer = NULL;
2163 }
2164}
2165
aliguori753b4052009-02-16 14:59:30 +00002166static void vnc_connect(VncDisplay *vd, int csock)
balrog3aa3eea2008-02-03 02:54:04 +00002167{
aliguori753b4052009-02-16 14:59:30 +00002168 VncState *vs = qemu_mallocz(sizeof(VncState));
2169 vs->csock = csock;
2170
2171 VNC_DEBUG("New client on socket %d\n", csock);
aliguori7d957bd2009-01-15 22:14:11 +00002172 dcl->idle = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002173 socket_set_nonblock(vs->csock);
2174 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
aliguori753b4052009-02-16 14:59:30 +00002175
2176 vs->vd = vd;
2177 vs->ds = vd->ds;
aliguori753b4052009-02-16 14:59:30 +00002178 vs->last_x = -1;
2179 vs->last_y = -1;
2180
2181 vs->as.freq = 44100;
2182 vs->as.nchannels = 2;
2183 vs->as.fmt = AUD_FMT_S16;
2184 vs->as.endianness = 0;
2185
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002186 vs->next = vd->clients;
2187 vd->clients = vs;
2188
2189 vga_hw_update();
2190
balrog3aa3eea2008-02-03 02:54:04 +00002191 vnc_write(vs, "RFB 003.008\n", 12);
2192 vnc_flush(vs);
2193 vnc_read_when(vs, protocol_version, 12);
malc53762dd2008-12-01 20:57:52 +00002194 reset_keys(vs);
aliguori753b4052009-02-16 14:59:30 +00002195
Stefano Stabellini703bc682009-08-03 10:54:05 +01002196 vnc_init_timer(vd);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002197
Gerd Hoffmann198a0032009-06-16 14:19:48 +02002198 /* vs might be free()ed here */
balrog3aa3eea2008-02-03 02:54:04 +00002199}
2200
bellard24236862006-04-30 21:28:36 +00002201static void vnc_listen_read(void *opaque)
2202{
aliguori753b4052009-02-16 14:59:30 +00002203 VncDisplay *vs = opaque;
bellard24236862006-04-30 21:28:36 +00002204 struct sockaddr_in addr;
2205 socklen_t addrlen = sizeof(addr);
2206
balrog9f60ad52008-01-14 21:45:55 +00002207 /* Catch-up */
2208 vga_hw_update();
2209
aliguori753b4052009-02-16 14:59:30 +00002210 int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
2211 if (csock != -1) {
2212 vnc_connect(vs, csock);
bellard24236862006-04-30 21:28:36 +00002213 }
2214}
2215
ths71cab5c2007-08-25 01:35:38 +00002216void vnc_display_init(DisplayState *ds)
bellard24236862006-04-30 21:28:36 +00002217{
Stefan Weilafd32162009-05-24 22:33:34 +02002218 VncDisplay *vs = qemu_mallocz(sizeof(*vs));
bellard24236862006-04-30 21:28:36 +00002219
aliguori7d957bd2009-01-15 22:14:11 +00002220 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
bellard24236862006-04-30 21:28:36 +00002221
2222 ds->opaque = vs;
aliguori7d957bd2009-01-15 22:14:11 +00002223 dcl->idle = 1;
aliguori753b4052009-02-16 14:59:30 +00002224 vnc_display = vs;
bellard24236862006-04-30 21:28:36 +00002225
2226 vs->lsock = -1;
bellard24236862006-04-30 21:28:36 +00002227
2228 vs->ds = ds;
2229
aliguori9ca313a2008-08-23 23:27:37 +00002230 if (keyboard_layout)
aliguori04837552009-03-06 20:27:10 +00002231 vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
aliguori9ca313a2008-08-23 23:27:37 +00002232 else
aliguori04837552009-03-06 20:27:10 +00002233 vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
bellard24236862006-04-30 21:28:36 +00002234
bellard24236862006-04-30 21:28:36 +00002235 if (!vs->kbd_layout)
aliguori28a76be2009-03-06 20:27:40 +00002236 exit(1);
bellard24236862006-04-30 21:28:36 +00002237
aliguori753b4052009-02-16 14:59:30 +00002238 dcl->dpy_copy = vnc_dpy_copy;
aliguori7d957bd2009-01-15 22:14:11 +00002239 dcl->dpy_update = vnc_dpy_update;
2240 dcl->dpy_resize = vnc_dpy_resize;
2241 dcl->dpy_setdata = vnc_dpy_setdata;
aliguori7d957bd2009-01-15 22:14:11 +00002242 register_displaychangelistener(ds, dcl);
ths71cab5c2007-08-25 01:35:38 +00002243}
ths73fc9742006-12-22 02:09:07 +00002244
ths6f430242007-08-25 01:39:57 +00002245
ths71cab5c2007-08-25 01:35:38 +00002246void vnc_display_close(DisplayState *ds)
2247{
aliguori753b4052009-02-16 14:59:30 +00002248 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths71cab5c2007-08-25 01:35:38 +00002249
aliguori452b4d82009-02-11 21:00:38 +00002250 if (!vs)
2251 return;
ths71cab5c2007-08-25 01:35:38 +00002252 if (vs->display) {
aliguori28a76be2009-03-06 20:27:40 +00002253 qemu_free(vs->display);
2254 vs->display = NULL;
ths71cab5c2007-08-25 01:35:38 +00002255 }
2256 if (vs->lsock != -1) {
aliguori28a76be2009-03-06 20:27:40 +00002257 qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
2258 close(vs->lsock);
2259 vs->lsock = -1;
ths71cab5c2007-08-25 01:35:38 +00002260 }
ths70848512007-08-25 01:37:05 +00002261 vs->auth = VNC_AUTH_INVALID;
blueswir1eb38c522008-09-06 17:47:39 +00002262#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002263 vs->subauth = VNC_AUTH_INVALID;
aliguori5fb6c7a2009-03-06 20:27:23 +00002264 vs->tls.x509verify = 0;
ths8d5d2d42007-08-25 01:37:51 +00002265#endif
ths71cab5c2007-08-25 01:35:38 +00002266}
2267
ths70848512007-08-25 01:37:05 +00002268int vnc_display_password(DisplayState *ds, const char *password)
2269{
aliguori753b4052009-02-16 14:59:30 +00002270 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths70848512007-08-25 01:37:05 +00002271
Zachary Amsden7ef92332009-07-30 00:15:00 -10002272 if (!vs) {
2273 return -1;
2274 }
2275
ths70848512007-08-25 01:37:05 +00002276 if (vs->password) {
aliguori28a76be2009-03-06 20:27:40 +00002277 qemu_free(vs->password);
2278 vs->password = NULL;
ths70848512007-08-25 01:37:05 +00002279 }
2280 if (password && password[0]) {
aliguori28a76be2009-03-06 20:27:40 +00002281 if (!(vs->password = qemu_strdup(password)))
2282 return -1;
Zachary Amsden52c18be2009-07-30 00:15:01 -10002283 if (vs->auth == VNC_AUTH_NONE) {
2284 vs->auth = VNC_AUTH_VNC;
2285 }
2286 } else {
2287 vs->auth = VNC_AUTH_NONE;
ths70848512007-08-25 01:37:05 +00002288 }
2289
2290 return 0;
2291}
2292
Anthony Liguorif92f8af2009-05-20 13:01:02 -05002293char *vnc_display_local_addr(DisplayState *ds)
2294{
2295 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
2296
2297 return vnc_socket_local_addr("%s:%s", vs->lsock);
2298}
2299
ths70848512007-08-25 01:37:05 +00002300int vnc_display_open(DisplayState *ds, const char *display)
ths71cab5c2007-08-25 01:35:38 +00002301{
aliguori753b4052009-02-16 14:59:30 +00002302 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths70848512007-08-25 01:37:05 +00002303 const char *options;
2304 int password = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002305 int reverse = 0;
aliguori9712eca2008-11-11 20:51:59 +00002306 int to_port = 0;
blueswir1eb38c522008-09-06 17:47:39 +00002307#ifdef CONFIG_VNC_TLS
ths3a702692007-08-25 01:38:36 +00002308 int tls = 0, x509 = 0;
ths8d5d2d42007-08-25 01:37:51 +00002309#endif
aliguori2f9606b2009-03-06 20:27:28 +00002310#ifdef CONFIG_VNC_SASL
2311 int sasl = 0;
2312 int saslErr;
2313#endif
aliguori76655d62009-03-06 20:27:37 +00002314 int acl = 0;
ths71cab5c2007-08-25 01:35:38 +00002315
aliguori753b4052009-02-16 14:59:30 +00002316 if (!vnc_display)
aliguori452b4d82009-02-11 21:00:38 +00002317 return -1;
ths71cab5c2007-08-25 01:35:38 +00002318 vnc_display_close(ds);
ths70848512007-08-25 01:37:05 +00002319 if (strcmp(display, "none") == 0)
aliguori28a76be2009-03-06 20:27:40 +00002320 return 0;
ths71cab5c2007-08-25 01:35:38 +00002321
ths70848512007-08-25 01:37:05 +00002322 if (!(vs->display = strdup(display)))
aliguori28a76be2009-03-06 20:27:40 +00002323 return -1;
ths70848512007-08-25 01:37:05 +00002324
2325 options = display;
2326 while ((options = strchr(options, ','))) {
aliguori28a76be2009-03-06 20:27:40 +00002327 options++;
2328 if (strncmp(options, "password", 8) == 0) {
2329 password = 1; /* Require password auth */
2330 } else if (strncmp(options, "reverse", 7) == 0) {
2331 reverse = 1;
2332 } else if (strncmp(options, "to=", 3) == 0) {
aliguori9712eca2008-11-11 20:51:59 +00002333 to_port = atoi(options+3) + 5900;
aliguori2f9606b2009-03-06 20:27:28 +00002334#ifdef CONFIG_VNC_SASL
aliguori28a76be2009-03-06 20:27:40 +00002335 } else if (strncmp(options, "sasl", 4) == 0) {
2336 sasl = 1; /* Require SASL auth */
aliguori2f9606b2009-03-06 20:27:28 +00002337#endif
blueswir1eb38c522008-09-06 17:47:39 +00002338#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002339 } else if (strncmp(options, "tls", 3) == 0) {
2340 tls = 1; /* Require TLS */
2341 } else if (strncmp(options, "x509", 4) == 0) {
2342 char *start, *end;
2343 x509 = 1; /* Require x509 certificates */
2344 if (strncmp(options, "x509verify", 10) == 0)
2345 vs->tls.x509verify = 1; /* ...and verify client certs */
ths6f430242007-08-25 01:39:57 +00002346
aliguori28a76be2009-03-06 20:27:40 +00002347 /* Now check for 'x509=/some/path' postfix
2348 * and use that to setup x509 certificate/key paths */
2349 start = strchr(options, '=');
2350 end = strchr(options, ',');
2351 if (start && (!end || (start < end))) {
2352 int len = end ? end-(start+1) : strlen(start+1);
2353 char *path = qemu_strndup(start + 1, len);
blueswir1be15b142008-10-25 11:21:28 +00002354
aliguori28a76be2009-03-06 20:27:40 +00002355 VNC_DEBUG("Trying certificate path '%s'\n", path);
2356 if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
2357 fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
2358 qemu_free(path);
2359 qemu_free(vs->display);
2360 vs->display = NULL;
2361 return -1;
2362 }
2363 qemu_free(path);
2364 } else {
2365 fprintf(stderr, "No certificate path provided\n");
2366 qemu_free(vs->display);
2367 vs->display = NULL;
2368 return -1;
2369 }
ths8d5d2d42007-08-25 01:37:51 +00002370#endif
aliguori28a76be2009-03-06 20:27:40 +00002371 } else if (strncmp(options, "acl", 3) == 0) {
2372 acl = 1;
2373 }
ths70848512007-08-25 01:37:05 +00002374 }
2375
aliguori76655d62009-03-06 20:27:37 +00002376#ifdef CONFIG_VNC_TLS
2377 if (acl && x509 && vs->tls.x509verify) {
aliguori28a76be2009-03-06 20:27:40 +00002378 if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
2379 fprintf(stderr, "Failed to create x509 dname ACL\n");
2380 exit(1);
2381 }
aliguori76655d62009-03-06 20:27:37 +00002382 }
2383#endif
2384#ifdef CONFIG_VNC_SASL
2385 if (acl && sasl) {
aliguori28a76be2009-03-06 20:27:40 +00002386 if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
2387 fprintf(stderr, "Failed to create username ACL\n");
2388 exit(1);
2389 }
aliguori76655d62009-03-06 20:27:37 +00002390 }
2391#endif
2392
aliguori2f9606b2009-03-06 20:27:28 +00002393 /*
2394 * Combinations we support here:
2395 *
2396 * - no-auth (clear text, no auth)
2397 * - password (clear text, weak auth)
2398 * - sasl (encrypt, good auth *IF* using Kerberos via GSSAPI)
2399 * - tls (encrypt, weak anonymous creds, no auth)
2400 * - tls + password (encrypt, weak anonymous creds, weak auth)
2401 * - tls + sasl (encrypt, weak anonymous creds, good auth)
2402 * - tls + x509 (encrypt, good x509 creds, no auth)
2403 * - tls + x509 + password (encrypt, good x509 creds, weak auth)
2404 * - tls + x509 + sasl (encrypt, good x509 creds, good auth)
2405 *
2406 * NB1. TLS is a stackable auth scheme.
2407 * NB2. the x509 schemes have option to validate a client cert dname
2408 */
ths70848512007-08-25 01:37:05 +00002409 if (password) {
blueswir1eb38c522008-09-06 17:47:39 +00002410#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002411 if (tls) {
2412 vs->auth = VNC_AUTH_VENCRYPT;
2413 if (x509) {
2414 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
2415 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
2416 } else {
2417 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
2418 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
2419 }
2420 } else {
aliguori2f9606b2009-03-06 20:27:28 +00002421#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00002422 VNC_DEBUG("Initializing VNC server with password auth\n");
2423 vs->auth = VNC_AUTH_VNC;
blueswir1eb38c522008-09-06 17:47:39 +00002424#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002425 vs->subauth = VNC_AUTH_INVALID;
2426 }
aliguori2f9606b2009-03-06 20:27:28 +00002427#endif /* CONFIG_VNC_TLS */
2428#ifdef CONFIG_VNC_SASL
2429 } else if (sasl) {
2430#ifdef CONFIG_VNC_TLS
2431 if (tls) {
2432 vs->auth = VNC_AUTH_VENCRYPT;
2433 if (x509) {
aliguori28a76be2009-03-06 20:27:40 +00002434 VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00002435 vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
2436 } else {
aliguori28a76be2009-03-06 20:27:40 +00002437 VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00002438 vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
2439 }
2440 } else {
2441#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00002442 VNC_DEBUG("Initializing VNC server with SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00002443 vs->auth = VNC_AUTH_SASL;
2444#ifdef CONFIG_VNC_TLS
2445 vs->subauth = VNC_AUTH_INVALID;
2446 }
2447#endif /* CONFIG_VNC_TLS */
2448#endif /* CONFIG_VNC_SASL */
ths70848512007-08-25 01:37:05 +00002449 } else {
blueswir1eb38c522008-09-06 17:47:39 +00002450#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002451 if (tls) {
2452 vs->auth = VNC_AUTH_VENCRYPT;
2453 if (x509) {
2454 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
2455 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
2456 } else {
2457 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
2458 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
2459 }
2460 } else {
ths8d5d2d42007-08-25 01:37:51 +00002461#endif
aliguori28a76be2009-03-06 20:27:40 +00002462 VNC_DEBUG("Initializing VNC server with no auth\n");
2463 vs->auth = VNC_AUTH_NONE;
blueswir1eb38c522008-09-06 17:47:39 +00002464#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002465 vs->subauth = VNC_AUTH_INVALID;
2466 }
ths8d5d2d42007-08-25 01:37:51 +00002467#endif
ths70848512007-08-25 01:37:05 +00002468 }
bellard24236862006-04-30 21:28:36 +00002469
aliguori2f9606b2009-03-06 20:27:28 +00002470#ifdef CONFIG_VNC_SASL
2471 if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
2472 fprintf(stderr, "Failed to initialize SASL auth %s",
2473 sasl_errstring(saslErr, NULL, NULL));
2474 free(vs->display);
2475 vs->display = NULL;
2476 return -1;
2477 }
2478#endif
2479
balrog3aa3eea2008-02-03 02:54:04 +00002480 if (reverse) {
aliguori9712eca2008-11-11 20:51:59 +00002481 /* connect to viewer */
2482 if (strncmp(display, "unix:", 5) == 0)
2483 vs->lsock = unix_connect(display+5);
2484 else
2485 vs->lsock = inet_connect(display, SOCK_STREAM);
2486 if (-1 == vs->lsock) {
balrog3aa3eea2008-02-03 02:54:04 +00002487 free(vs->display);
2488 vs->display = NULL;
2489 return -1;
2490 } else {
aliguori753b4052009-02-16 14:59:30 +00002491 int csock = vs->lsock;
balrog3aa3eea2008-02-03 02:54:04 +00002492 vs->lsock = -1;
aliguori753b4052009-02-16 14:59:30 +00002493 vnc_connect(vs, csock);
balrog3aa3eea2008-02-03 02:54:04 +00002494 }
aliguori9712eca2008-11-11 20:51:59 +00002495 return 0;
balrog3aa3eea2008-02-03 02:54:04 +00002496
aliguori9712eca2008-11-11 20:51:59 +00002497 } else {
2498 /* listen for connects */
2499 char *dpy;
2500 dpy = qemu_malloc(256);
2501 if (strncmp(display, "unix:", 5) == 0) {
blueswir1bc575e92009-01-14 18:34:22 +00002502 pstrcpy(dpy, 256, "unix:");
aliguori4a55bfd2008-12-02 20:02:14 +00002503 vs->lsock = unix_listen(display+5, dpy+5, 256-5);
aliguori9712eca2008-11-11 20:51:59 +00002504 } else {
2505 vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
2506 }
2507 if (-1 == vs->lsock) {
2508 free(dpy);
balrogd0513622008-12-01 01:48:36 +00002509 return -1;
aliguori9712eca2008-11-11 20:51:59 +00002510 } else {
2511 free(vs->display);
2512 vs->display = dpy;
2513 }
bellard24236862006-04-30 21:28:36 +00002514 }
aliguori753b4052009-02-16 14:59:30 +00002515 return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00002516}