blob: d5f7adfef682b300937782f46351cf7c9e4126cc [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
ths5fafdf22007-09-16 21:08:06 +00006 *
bellard7d510b82006-05-01 10:38:19 +00007 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
pbrook87ecb682007-11-17 17:14:51 +000026#include "qemu-common.h"
aliguori376253e2009-03-05 23:01:23 +000027#include "monitor.h"
pbrook87ecb682007-11-17 17:14:51 +000028#include "console.h"
29#include "sysemu.h"
bellard6ca957f2006-04-30 22:53:25 +000030#include "qemu_socket.h"
pbrook87ecb682007-11-17 17:14:51 +000031#include "qemu-timer.h"
malc429a8ed2008-12-01 20:57:48 +000032#include "audio/audio.h"
aliguori059cef42009-02-02 15:58:54 +000033#include <zlib.h>
bellard24236862006-04-30 21:28:36 +000034
35#define VNC_REFRESH_INTERVAL (1000 / 30)
36
aliguorie06679f2009-02-02 15:58:25 +000037#include "vnc.h"
bellard24236862006-04-30 21:28:36 +000038#include "vnc_keysym.h"
39#include "keymaps.c"
ths70848512007-08-25 01:37:05 +000040#include "d3des.h"
41
blueswir1eb38c522008-09-06 17:47:39 +000042#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +000043#include <gnutls/gnutls.h>
44#include <gnutls/x509.h>
45#endif /* CONFIG_VNC_TLS */
ths70848512007-08-25 01:37:05 +000046
ths8d5d2d42007-08-25 01:37:51 +000047// #define _VNC_DEBUG 1
48
blueswir1eb38c522008-09-06 17:47:39 +000049#ifdef _VNC_DEBUG
ths70848512007-08-25 01:37:05 +000050#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
ths8d5d2d42007-08-25 01:37:51 +000051
aliguori26f8b9c2009-02-02 15:58:38 +000052#if defined(CONFIG_VNC_TLS) && _VNC_DEBUG >= 2
ths8d5d2d42007-08-25 01:37:51 +000053/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
54static void vnc_debug_gnutls_log(int level, const char* str) {
55 VNC_DEBUG("%d %s", level, str);
56}
57#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
ths70848512007-08-25 01:37:05 +000058#else
59#define VNC_DEBUG(fmt, ...) do { } while (0)
60#endif
bellard24236862006-04-30 21:28:36 +000061
aliguori90a1e3c2009-01-26 15:37:30 +000062#define count_bits(c, v) { \
63 for (c = 0; v; v >>= 1) \
64 { \
65 c += v & 1; \
66 } \
67}
ths8d5d2d42007-08-25 01:37:51 +000068
bellard24236862006-04-30 21:28:36 +000069typedef struct Buffer
70{
71 size_t capacity;
72 size_t offset;
ths60fe76f2007-12-16 03:02:09 +000073 uint8_t *buffer;
bellard24236862006-04-30 21:28:36 +000074} Buffer;
75
76typedef struct VncState VncState;
77
ths60fe76f2007-12-16 03:02:09 +000078typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
bellard24236862006-04-30 21:28:36 +000079
bellard35127792006-05-14 18:11:49 +000080typedef void VncWritePixels(VncState *vs, void *data, int size);
81
82typedef void VncSendHextileTile(VncState *vs,
83 int x, int y, int w, int h,
aliguori7eac3a82008-09-15 16:03:41 +000084 void *last_bg,
85 void *last_fg,
bellard35127792006-05-14 18:11:49 +000086 int *has_bg, int *has_fg);
87
bellard99589bd2006-06-13 16:35:24 +000088#define VNC_MAX_WIDTH 2048
89#define VNC_MAX_HEIGHT 2048
90#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
91
ths70848512007-08-25 01:37:05 +000092#define VNC_AUTH_CHALLENGE_SIZE 16
93
aliguori753b4052009-02-16 14:59:30 +000094typedef struct VncDisplay VncDisplay;
95
96struct VncDisplay
97{
98 int lsock;
99 DisplayState *ds;
100 VncState *clients;
101 kbd_layout_t *kbd_layout;
102
103 char *display;
104 char *password;
105 int auth;
106#ifdef CONFIG_VNC_TLS
107 int subauth;
108 int x509verify;
109
110 char *x509cacert;
111 char *x509cacrl;
112 char *x509cert;
113 char *x509key;
114#endif
115};
116
bellard24236862006-04-30 21:28:36 +0000117struct VncState
118{
119 QEMUTimer *timer;
bellard24236862006-04-30 21:28:36 +0000120 int csock;
121 DisplayState *ds;
aliguori753b4052009-02-16 14:59:30 +0000122 VncDisplay *vd;
bellard24236862006-04-30 21:28:36 +0000123 int need_update;
bellard99589bd2006-06-13 16:35:24 +0000124 uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
bellard24236862006-04-30 21:28:36 +0000125 char *old_data;
aliguori29fa4ed2009-02-02 15:58:29 +0000126 uint32_t features;
bellard564c3372007-02-05 20:14:10 +0000127 int absolute;
128 int last_x;
129 int last_y;
130
aliguorifb437312009-02-02 15:58:43 +0000131 uint32_t vnc_encoding;
132 uint8_t tight_quality;
133 uint8_t tight_compression;
134
ths70848512007-08-25 01:37:05 +0000135 int major;
136 int minor;
137
ths70848512007-08-25 01:37:05 +0000138 char challenge[VNC_AUTH_CHALLENGE_SIZE];
bellarda9ce8592007-02-05 20:20:30 +0000139
blueswir1eb38c522008-09-06 17:47:39 +0000140#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000141 int wiremode;
142 gnutls_session_t tls_session;
143#endif
144
bellard24236862006-04-30 21:28:36 +0000145 Buffer output;
146 Buffer input;
bellard35127792006-05-14 18:11:49 +0000147 /* current output mode information */
148 VncWritePixels *write_pixels;
149 VncSendHextileTile *send_hextile_tile;
aliguori6cec5482009-01-15 22:17:38 +0000150 DisplaySurface clientds, serverds;
bellard24236862006-04-30 21:28:36 +0000151
malc429a8ed2008-12-01 20:57:48 +0000152 CaptureVoiceOut *audio_cap;
malc1ea879e2008-12-03 22:48:44 +0000153 struct audsettings as;
malc429a8ed2008-12-01 20:57:48 +0000154
bellard24236862006-04-30 21:28:36 +0000155 VncReadEvent *read_handler;
156 size_t read_handler_expect;
bellard64f5a132006-08-24 20:36:44 +0000157 /* input */
158 uint8_t modifiers_state[256];
aliguori059cef42009-02-02 15:58:54 +0000159
160 Buffer zlib;
161 Buffer zlib_tmp;
162 z_stream zlib_stream[4];
aliguori753b4052009-02-16 14:59:30 +0000163
164 VncState *next;
bellard24236862006-04-30 21:28:36 +0000165};
166
aliguori753b4052009-02-16 14:59:30 +0000167static VncDisplay *vnc_display; /* needed for info vnc */
aliguori7d957bd2009-01-15 22:14:11 +0000168static DisplayChangeListener *dcl;
bellarda9ce8592007-02-05 20:20:30 +0000169
aliguori1ff7df12009-03-06 20:27:05 +0000170static char *addr_to_string(const char *format,
171 struct sockaddr_storage *sa,
172 socklen_t salen) {
173 char *addr;
174 char host[NI_MAXHOST];
175 char serv[NI_MAXSERV];
176 int err;
177
178 if ((err = getnameinfo((struct sockaddr *)sa, salen,
179 host, sizeof(host),
180 serv, sizeof(serv),
181 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
182 VNC_DEBUG("Cannot resolve address %d: %s\n",
183 err, gai_strerror(err));
184 return NULL;
185 }
186
187 if (asprintf(&addr, format, host, serv) < 0)
188 return NULL;
189
190 return addr;
191}
192
193static char *vnc_socket_local_addr(const char *format, int fd) {
194 struct sockaddr_storage sa;
195 socklen_t salen;
196
197 salen = sizeof(sa);
198 if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
199 return NULL;
200
201 return addr_to_string(format, &sa, salen);
202}
203
204static char *vnc_socket_remote_addr(const char *format, int fd) {
205 struct sockaddr_storage sa;
206 socklen_t salen;
207
208 salen = sizeof(sa);
209 if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
210 return NULL;
211
212 return addr_to_string(format, &sa, salen);
213}
214
215static const char *vnc_auth_name(VncDisplay *vd) {
216 switch (vd->auth) {
217 case VNC_AUTH_INVALID:
218 return "invalid";
219 case VNC_AUTH_NONE:
220 return "none";
221 case VNC_AUTH_VNC:
222 return "vnc";
223 case VNC_AUTH_RA2:
224 return "ra2";
225 case VNC_AUTH_RA2NE:
226 return "ra2ne";
227 case VNC_AUTH_TIGHT:
228 return "tight";
229 case VNC_AUTH_ULTRA:
230 return "ultra";
231 case VNC_AUTH_TLS:
232 return "tls";
233 case VNC_AUTH_VENCRYPT:
234#ifdef CONFIG_VNC_TLS
235 switch (vd->subauth) {
236 case VNC_AUTH_VENCRYPT_PLAIN:
237 return "vencrypt+plain";
238 case VNC_AUTH_VENCRYPT_TLSNONE:
239 return "vencrypt+tls+none";
240 case VNC_AUTH_VENCRYPT_TLSVNC:
241 return "vencrypt+tls+vnc";
242 case VNC_AUTH_VENCRYPT_TLSPLAIN:
243 return "vencrypt+tls+plain";
244 case VNC_AUTH_VENCRYPT_X509NONE:
245 return "vencrypt+x509+none";
246 case VNC_AUTH_VENCRYPT_X509VNC:
247 return "vencrypt+x509+vnc";
248 case VNC_AUTH_VENCRYPT_X509PLAIN:
249 return "vencrypt+x509+plain";
250 default:
251 return "vencrypt";
252 }
253#else
254 return "vencrypt";
255#endif
256 }
257 return "unknown";
258}
259
260#define VNC_SOCKET_FORMAT_PRETTY "local %s:%s"
261
262static void do_info_vnc_client(Monitor *mon, VncState *client)
263{
264 char *clientAddr =
265 vnc_socket_remote_addr(" address: %s:%s\n",
266 client->csock);
267 if (!clientAddr)
268 return;
269
270 monitor_printf(mon, "Client:\n");
271 monitor_printf(mon, "%s", clientAddr);
272 free(clientAddr);
273}
274
aliguori376253e2009-03-05 23:01:23 +0000275void do_info_vnc(Monitor *mon)
bellarda9ce8592007-02-05 20:20:30 +0000276{
aliguori1ff7df12009-03-06 20:27:05 +0000277 if (vnc_display == NULL || vnc_display->display == NULL) {
278 monitor_printf(mon, "Server: disabled\n");
279 } else {
280 char *serverAddr = vnc_socket_local_addr(" address: %s:%s\n",
281 vnc_display->lsock);
bellarda9ce8592007-02-05 20:20:30 +0000282
aliguori1ff7df12009-03-06 20:27:05 +0000283 if (!serverAddr)
284 return;
285
286 monitor_printf(mon, "Server:\n");
287 monitor_printf(mon, "%s", serverAddr);
288 free(serverAddr);
289 monitor_printf(mon, " auth: %s\n", vnc_auth_name(vnc_display));
290
291 if (vnc_display->clients) {
292 VncState *client = vnc_display->clients;
293 while (client) {
294 do_info_vnc_client(mon, client);
295 client = client->next;
296 }
297 } else {
298 monitor_printf(mon, "Client: none\n");
299 }
bellarda9ce8592007-02-05 20:20:30 +0000300 }
301}
302
aliguori29fa4ed2009-02-02 15:58:29 +0000303static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
304 return (vs->features & (1 << feature));
305}
306
bellard24236862006-04-30 21:28:36 +0000307/* TODO
308 1) Get the queue working for IO.
309 2) there is some weirdness when using the -S option (the screen is grey
310 and not totally invalidated
311 3) resolutions > 1024
312*/
313
314static void vnc_write(VncState *vs, const void *data, size_t len);
315static void vnc_write_u32(VncState *vs, uint32_t value);
316static void vnc_write_s32(VncState *vs, int32_t value);
317static void vnc_write_u16(VncState *vs, uint16_t value);
318static void vnc_write_u8(VncState *vs, uint8_t value);
319static void vnc_flush(VncState *vs);
320static void vnc_update_client(void *opaque);
321static void vnc_client_read(void *opaque);
322
aliguori753b4052009-02-16 14:59:30 +0000323static void vnc_colordepth(VncState *vs);
aliguori7eac3a82008-09-15 16:03:41 +0000324
bellard99589bd2006-06-13 16:35:24 +0000325static inline void vnc_set_bit(uint32_t *d, int k)
326{
327 d[k >> 5] |= 1 << (k & 0x1f);
328}
329
330static inline void vnc_clear_bit(uint32_t *d, int k)
331{
332 d[k >> 5] &= ~(1 << (k & 0x1f));
333}
334
335static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
336{
337 int j;
338
339 j = 0;
340 while (n >= 32) {
341 d[j++] = -1;
342 n -= 32;
343 }
ths5fafdf22007-09-16 21:08:06 +0000344 if (n > 0)
bellard99589bd2006-06-13 16:35:24 +0000345 d[j++] = (1 << n) - 1;
346 while (j < nb_words)
347 d[j++] = 0;
348}
349
350static inline int vnc_get_bit(const uint32_t *d, int k)
351{
352 return (d[k >> 5] >> (k & 0x1f)) & 1;
353}
354
ths5fafdf22007-09-16 21:08:06 +0000355static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
bellard99589bd2006-06-13 16:35:24 +0000356 int nb_words)
357{
358 int i;
359 for(i = 0; i < nb_words; i++) {
360 if ((d1[i] & d2[i]) != 0)
361 return 1;
362 }
363 return 0;
364}
365
aliguori753b4052009-02-16 14:59:30 +0000366static void vnc_update(VncState *vs, int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000367{
bellard24236862006-04-30 21:28:36 +0000368 int i;
369
370 h += y;
371
balrog0486e8a2007-12-11 22:31:32 +0000372 /* round x down to ensure the loop only spans one 16-pixel block per,
373 iteration. otherwise, if (x % 16) != 0, the last iteration may span
374 two 16-pixel blocks but we only mark the first as dirty
375 */
376 w += (x % 16);
377 x -= (x % 16);
378
aliguori6cec5482009-01-15 22:17:38 +0000379 x = MIN(x, vs->serverds.width);
380 y = MIN(y, vs->serverds.height);
381 w = MIN(x + w, vs->serverds.width) - x;
382 h = MIN(h, vs->serverds.height);
balrog788abf82008-05-20 00:07:58 +0000383
bellard24236862006-04-30 21:28:36 +0000384 for (; y < h; y++)
385 for (i = 0; i < w; i += 16)
bellard99589bd2006-06-13 16:35:24 +0000386 vnc_set_bit(vs->dirty_row[y], (x + i) / 16);
bellard24236862006-04-30 21:28:36 +0000387}
388
aliguori753b4052009-02-16 14:59:30 +0000389static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
390{
391 VncDisplay *vd = ds->opaque;
392 VncState *vs = vd->clients;
393 while (vs != NULL) {
394 vnc_update(vs, x, y, w, h);
395 vs = vs->next;
396 }
397}
398
bellard24236862006-04-30 21:28:36 +0000399static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
400 int32_t encoding)
401{
402 vnc_write_u16(vs, x);
403 vnc_write_u16(vs, y);
404 vnc_write_u16(vs, w);
405 vnc_write_u16(vs, h);
406
407 vnc_write_s32(vs, encoding);
408}
409
aliguori89064282009-02-02 15:58:47 +0000410static void buffer_reserve(Buffer *buffer, size_t len)
411{
412 if ((buffer->capacity - buffer->offset) < len) {
413 buffer->capacity += (len + 1024);
414 buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
415 if (buffer->buffer == NULL) {
416 fprintf(stderr, "vnc: out of memory\n");
417 exit(1);
418 }
419 }
420}
421
422static int buffer_empty(Buffer *buffer)
423{
424 return buffer->offset == 0;
425}
426
427static uint8_t *buffer_end(Buffer *buffer)
428{
429 return buffer->buffer + buffer->offset;
430}
431
432static void buffer_reset(Buffer *buffer)
433{
434 buffer->offset = 0;
435}
436
437static void buffer_append(Buffer *buffer, const void *data, size_t len)
438{
439 memcpy(buffer->buffer + buffer->offset, data, len);
440 buffer->offset += len;
441}
442
aliguori753b4052009-02-16 14:59:30 +0000443static void vnc_resize(VncState *vs)
bellard24236862006-04-30 21:28:36 +0000444{
aliguori753b4052009-02-16 14:59:30 +0000445 DisplayState *ds = vs->ds;
446
ths73e14b62006-12-14 13:36:01 +0000447 int size_changed;
bellard24236862006-04-30 21:28:36 +0000448
aliguori7d957bd2009-01-15 22:14:11 +0000449 vs->old_data = qemu_realloc(vs->old_data, ds_get_linesize(ds) * ds_get_height(ds));
bellard24236862006-04-30 21:28:36 +0000450
aliguori7d957bd2009-01-15 22:14:11 +0000451 if (vs->old_data == NULL) {
bellard24236862006-04-30 21:28:36 +0000452 fprintf(stderr, "vnc: memory allocation failed\n");
453 exit(1);
454 }
455
aliguori6cec5482009-01-15 22:17:38 +0000456 if (ds_get_bytes_per_pixel(ds) != vs->serverds.pf.bytes_per_pixel)
balroga528b802007-10-30 22:38:53 +0000457 console_color_init(ds);
aliguori753b4052009-02-16 14:59:30 +0000458 vnc_colordepth(vs);
aliguori6cec5482009-01-15 22:17:38 +0000459 size_changed = ds_get_width(ds) != vs->serverds.width ||
460 ds_get_height(ds) != vs->serverds.height;
461 vs->serverds = *(ds->surface);
balrogb94eb432008-06-02 01:40:29 +0000462 if (size_changed) {
aliguori29fa4ed2009-02-02 15:58:29 +0000463 if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
balrogb94eb432008-06-02 01:40:29 +0000464 vnc_write_u8(vs, 0); /* msg id */
465 vnc_write_u8(vs, 0);
466 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000467 vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
468 VNC_ENCODING_DESKTOPRESIZE);
balrogb94eb432008-06-02 01:40:29 +0000469 vnc_flush(vs);
470 }
bellard24236862006-04-30 21:28:36 +0000471 }
balrog8bba5c82008-05-25 00:14:34 +0000472
473 memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
aliguori0e1f5a02008-11-24 19:29:13 +0000474 memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
bellard24236862006-04-30 21:28:36 +0000475}
476
aliguori753b4052009-02-16 14:59:30 +0000477static void vnc_dpy_resize(DisplayState *ds)
478{
479 VncDisplay *vd = ds->opaque;
480 VncState *vs = vd->clients;
481 while (vs != NULL) {
482 vnc_resize(vs);
483 vs = vs->next;
484 }
485}
486
bellard35127792006-05-14 18:11:49 +0000487/* fastest code */
488static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
489{
490 vnc_write(vs, pixels, size);
491}
492
493/* slowest but generic code. */
494static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
495{
aliguori7eac3a82008-09-15 16:03:41 +0000496 uint8_t r, g, b;
bellard35127792006-05-14 18:11:49 +0000497
aliguori90a1e3c2009-01-26 15:37:30 +0000498 r = ((((v & vs->serverds.pf.rmask) >> vs->serverds.pf.rshift) << vs->clientds.pf.rbits) >>
499 vs->serverds.pf.rbits);
500 g = ((((v & vs->serverds.pf.gmask) >> vs->serverds.pf.gshift) << vs->clientds.pf.gbits) >>
501 vs->serverds.pf.gbits);
502 b = ((((v & vs->serverds.pf.bmask) >> vs->serverds.pf.bshift) << vs->clientds.pf.bbits) >>
503 vs->serverds.pf.bbits);
aliguori6cec5482009-01-15 22:17:38 +0000504 v = (r << vs->clientds.pf.rshift) |
505 (g << vs->clientds.pf.gshift) |
506 (b << vs->clientds.pf.bshift);
507 switch(vs->clientds.pf.bytes_per_pixel) {
bellard35127792006-05-14 18:11:49 +0000508 case 1:
509 buf[0] = v;
510 break;
511 case 2:
aliguori6cec5482009-01-15 22:17:38 +0000512 if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
bellard35127792006-05-14 18:11:49 +0000513 buf[0] = v >> 8;
514 buf[1] = v;
515 } else {
516 buf[1] = v >> 8;
517 buf[0] = v;
518 }
519 break;
520 default:
521 case 4:
aliguori6cec5482009-01-15 22:17:38 +0000522 if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
bellard35127792006-05-14 18:11:49 +0000523 buf[0] = v >> 24;
524 buf[1] = v >> 16;
525 buf[2] = v >> 8;
526 buf[3] = v;
527 } else {
528 buf[3] = v >> 24;
529 buf[2] = v >> 16;
530 buf[1] = v >> 8;
531 buf[0] = v;
532 }
533 break;
534 }
535}
536
537static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
538{
bellard35127792006-05-14 18:11:49 +0000539 uint8_t buf[4];
bellard35127792006-05-14 18:11:49 +0000540
aliguori6cec5482009-01-15 22:17:38 +0000541 if (vs->serverds.pf.bytes_per_pixel == 4) {
aliguori7eac3a82008-09-15 16:03:41 +0000542 uint32_t *pixels = pixels1;
543 int n, i;
544 n = size >> 2;
545 for(i = 0; i < n; i++) {
546 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000547 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000548 }
aliguori6cec5482009-01-15 22:17:38 +0000549 } else if (vs->serverds.pf.bytes_per_pixel == 2) {
aliguori7eac3a82008-09-15 16:03:41 +0000550 uint16_t *pixels = pixels1;
551 int n, i;
552 n = size >> 1;
553 for(i = 0; i < n; i++) {
554 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000555 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000556 }
aliguori6cec5482009-01-15 22:17:38 +0000557 } else if (vs->serverds.pf.bytes_per_pixel == 1) {
aliguori7eac3a82008-09-15 16:03:41 +0000558 uint8_t *pixels = pixels1;
559 int n, i;
560 n = size;
561 for(i = 0; i < n; i++) {
562 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000563 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000564 }
565 } else {
566 fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
bellard35127792006-05-14 18:11:49 +0000567 }
568}
569
bellard24236862006-04-30 21:28:36 +0000570static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
571{
572 int i;
ths60fe76f2007-12-16 03:02:09 +0000573 uint8_t *row;
bellard24236862006-04-30 21:28:36 +0000574
aliguori6cec5482009-01-15 22:17:38 +0000575 row = ds_get_data(vs->ds) + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
bellard24236862006-04-30 21:28:36 +0000576 for (i = 0; i < h; i++) {
aliguori6cec5482009-01-15 22:17:38 +0000577 vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
aliguori0e1f5a02008-11-24 19:29:13 +0000578 row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +0000579 }
580}
581
582static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
583{
584 ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
585 ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
586}
587
588#define BPP 8
589#include "vnchextile.h"
590#undef BPP
591
592#define BPP 16
593#include "vnchextile.h"
594#undef BPP
595
596#define BPP 32
597#include "vnchextile.h"
598#undef BPP
599
bellard35127792006-05-14 18:11:49 +0000600#define GENERIC
aliguori7eac3a82008-09-15 16:03:41 +0000601#define BPP 8
602#include "vnchextile.h"
603#undef BPP
604#undef GENERIC
605
606#define GENERIC
607#define BPP 16
608#include "vnchextile.h"
609#undef BPP
610#undef GENERIC
611
612#define GENERIC
bellard35127792006-05-14 18:11:49 +0000613#define BPP 32
614#include "vnchextile.h"
615#undef BPP
616#undef GENERIC
617
bellard24236862006-04-30 21:28:36 +0000618static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
619{
620 int i, j;
621 int has_fg, has_bg;
aliguori7eac3a82008-09-15 16:03:41 +0000622 uint8_t *last_fg, *last_bg;
bellard24236862006-04-30 21:28:36 +0000623
aliguori1eec6142009-02-05 22:06:18 +0000624 last_fg = (uint8_t *) qemu_malloc(vs->serverds.pf.bytes_per_pixel);
625 last_bg = (uint8_t *) qemu_malloc(vs->serverds.pf.bytes_per_pixel);
bellard24236862006-04-30 21:28:36 +0000626 has_fg = has_bg = 0;
627 for (j = y; j < (y + h); j += 16) {
628 for (i = x; i < (x + w); i += 16) {
ths5fafdf22007-09-16 21:08:06 +0000629 vs->send_hextile_tile(vs, i, j,
bellard35127792006-05-14 18:11:49 +0000630 MIN(16, x + w - i), MIN(16, y + h - j),
aliguori7eac3a82008-09-15 16:03:41 +0000631 last_bg, last_fg, &has_bg, &has_fg);
bellard24236862006-04-30 21:28:36 +0000632 }
633 }
aliguori7eac3a82008-09-15 16:03:41 +0000634 free(last_fg);
635 free(last_bg);
636
bellard24236862006-04-30 21:28:36 +0000637}
638
aliguori059cef42009-02-02 15:58:54 +0000639static void vnc_zlib_init(VncState *vs)
640{
641 int i;
642 for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++)
643 vs->zlib_stream[i].opaque = NULL;
644}
645
646static void vnc_zlib_start(VncState *vs)
647{
648 buffer_reset(&vs->zlib);
649
650 // make the output buffer be the zlib buffer, so we can compress it later
651 vs->zlib_tmp = vs->output;
652 vs->output = vs->zlib;
653}
654
655static int vnc_zlib_stop(VncState *vs, int stream_id)
656{
657 z_streamp zstream = &vs->zlib_stream[stream_id];
658 int previous_out;
659
660 // switch back to normal output/zlib buffers
661 vs->zlib = vs->output;
662 vs->output = vs->zlib_tmp;
663
664 // compress the zlib buffer
665
666 // initialize the stream
667 // XXX need one stream per session
668 if (zstream->opaque != vs) {
669 int err;
670
671 VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
672 VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
673 zstream->zalloc = Z_NULL;
674 zstream->zfree = Z_NULL;
675
676 err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
677 MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
678
679 if (err != Z_OK) {
680 fprintf(stderr, "VNC: error initializing zlib\n");
681 return -1;
682 }
683
684 zstream->opaque = vs;
685 }
686
687 // XXX what to do if tight_compression changed in between?
688
689 // reserve memory in output buffer
690 buffer_reserve(&vs->output, vs->zlib.offset + 64);
691
692 // set pointers
693 zstream->next_in = vs->zlib.buffer;
694 zstream->avail_in = vs->zlib.offset;
695 zstream->next_out = vs->output.buffer + vs->output.offset;
696 zstream->avail_out = vs->output.capacity - vs->output.offset;
697 zstream->data_type = Z_BINARY;
698 previous_out = zstream->total_out;
699
700 // start encoding
701 if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
702 fprintf(stderr, "VNC: error during zlib compression\n");
703 return -1;
704 }
705
706 vs->output.offset = vs->output.capacity - zstream->avail_out;
707 return zstream->total_out - previous_out;
708}
709
710static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h)
711{
712 int old_offset, new_offset, bytes_written;
713
714 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
715
716 // remember where we put in the follow-up size
717 old_offset = vs->output.offset;
718 vnc_write_s32(vs, 0);
719
720 // compress the stream
721 vnc_zlib_start(vs);
722 send_framebuffer_update_raw(vs, x, y, w, h);
723 bytes_written = vnc_zlib_stop(vs, 0);
724
725 if (bytes_written == -1)
726 return;
727
728 // hack in the size
729 new_offset = vs->output.offset;
730 vs->output.offset = old_offset;
731 vnc_write_u32(vs, bytes_written);
732 vs->output.offset = new_offset;
733}
734
bellard24236862006-04-30 21:28:36 +0000735static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
736{
aliguorifb437312009-02-02 15:58:43 +0000737 switch(vs->vnc_encoding) {
aliguori059cef42009-02-02 15:58:54 +0000738 case VNC_ENCODING_ZLIB:
739 send_framebuffer_update_zlib(vs, x, y, w, h);
740 break;
aliguorifb437312009-02-02 15:58:43 +0000741 case VNC_ENCODING_HEXTILE:
aliguorid2a01022009-02-02 15:58:51 +0000742 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
bellard24236862006-04-30 21:28:36 +0000743 send_framebuffer_update_hextile(vs, x, y, w, h);
aliguorifb437312009-02-02 15:58:43 +0000744 break;
745 default:
aliguorid2a01022009-02-02 15:58:51 +0000746 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
bellard24236862006-04-30 21:28:36 +0000747 send_framebuffer_update_raw(vs, x, y, w, h);
aliguorifb437312009-02-02 15:58:43 +0000748 break;
749 }
bellard24236862006-04-30 21:28:36 +0000750}
751
aliguori753b4052009-02-16 14:59:30 +0000752static 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 +0000753{
bellard24236862006-04-30 21:28:36 +0000754 vnc_update_client(vs);
755
bellard24236862006-04-30 21:28:36 +0000756 vnc_write_u8(vs, 0); /* msg id */
757 vnc_write_u8(vs, 0);
758 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000759 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
bellard24236862006-04-30 21:28:36 +0000760 vnc_write_u16(vs, src_x);
761 vnc_write_u16(vs, src_y);
762 vnc_flush(vs);
763}
764
aliguori753b4052009-02-16 14:59:30 +0000765static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
766{
767 VncDisplay *vd = ds->opaque;
768 VncState *vs = vd->clients;
769 while (vs != NULL) {
770 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
771 vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
772 else /* TODO */
773 vnc_update(vs, dst_x, dst_y, w, h);
774 vs = vs->next;
775 }
776}
777
bellard24236862006-04-30 21:28:36 +0000778static int find_dirty_height(VncState *vs, int y, int last_x, int x)
779{
780 int h;
781
aliguori6cec5482009-01-15 22:17:38 +0000782 for (h = 1; h < (vs->serverds.height - y); h++) {
bellard24236862006-04-30 21:28:36 +0000783 int tmp_x;
bellard99589bd2006-06-13 16:35:24 +0000784 if (!vnc_get_bit(vs->dirty_row[y + h], last_x))
bellard24236862006-04-30 21:28:36 +0000785 break;
786 for (tmp_x = last_x; tmp_x < x; tmp_x++)
bellard99589bd2006-06-13 16:35:24 +0000787 vnc_clear_bit(vs->dirty_row[y + h], tmp_x);
bellard24236862006-04-30 21:28:36 +0000788 }
789
790 return h;
791}
792
793static void vnc_update_client(void *opaque)
794{
795 VncState *vs = opaque;
bellard24236862006-04-30 21:28:36 +0000796 if (vs->need_update && vs->csock != -1) {
797 int y;
ths60fe76f2007-12-16 03:02:09 +0000798 uint8_t *row;
bellard24236862006-04-30 21:28:36 +0000799 char *old_row;
bellard99589bd2006-06-13 16:35:24 +0000800 uint32_t width_mask[VNC_DIRTY_WORDS];
bellard24236862006-04-30 21:28:36 +0000801 int n_rectangles;
802 int saved_offset;
803 int has_dirty = 0;
804
balroga0ecfb72008-01-13 23:51:53 +0000805 vga_hw_update();
806
aliguori6cec5482009-01-15 22:17:38 +0000807 vnc_set_bits(width_mask, (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
bellard24236862006-04-30 21:28:36 +0000808
809 /* Walk through the dirty map and eliminate tiles that
810 really aren't dirty */
aliguori0e1f5a02008-11-24 19:29:13 +0000811 row = ds_get_data(vs->ds);
bellard24236862006-04-30 21:28:36 +0000812 old_row = vs->old_data;
813
aliguori6cec5482009-01-15 22:17:38 +0000814 for (y = 0; y < ds_get_height(vs->ds); y++) {
bellard99589bd2006-06-13 16:35:24 +0000815 if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) {
bellard24236862006-04-30 21:28:36 +0000816 int x;
ths60fe76f2007-12-16 03:02:09 +0000817 uint8_t *ptr;
818 char *old_ptr;
bellard24236862006-04-30 21:28:36 +0000819
820 ptr = row;
ths60fe76f2007-12-16 03:02:09 +0000821 old_ptr = (char*)old_row;
bellard24236862006-04-30 21:28:36 +0000822
aliguori0e1f5a02008-11-24 19:29:13 +0000823 for (x = 0; x < ds_get_width(vs->ds); x += 16) {
aliguori6cec5482009-01-15 22:17:38 +0000824 if (memcmp(old_ptr, ptr, 16 * ds_get_bytes_per_pixel(vs->ds)) == 0) {
bellard99589bd2006-06-13 16:35:24 +0000825 vnc_clear_bit(vs->dirty_row[y], (x / 16));
bellard24236862006-04-30 21:28:36 +0000826 } else {
827 has_dirty = 1;
aliguori6cec5482009-01-15 22:17:38 +0000828 memcpy(old_ptr, ptr, 16 * ds_get_bytes_per_pixel(vs->ds));
bellard24236862006-04-30 21:28:36 +0000829 }
830
aliguori6cec5482009-01-15 22:17:38 +0000831 ptr += 16 * ds_get_bytes_per_pixel(vs->ds);
832 old_ptr += 16 * ds_get_bytes_per_pixel(vs->ds);
bellard24236862006-04-30 21:28:36 +0000833 }
834 }
835
aliguori0e1f5a02008-11-24 19:29:13 +0000836 row += ds_get_linesize(vs->ds);
837 old_row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +0000838 }
839
malc429a8ed2008-12-01 20:57:48 +0000840 if (!has_dirty && !vs->audio_cap) {
bellard24236862006-04-30 21:28:36 +0000841 qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
842 return;
843 }
844
845 /* Count rectangles */
846 n_rectangles = 0;
847 vnc_write_u8(vs, 0); /* msg id */
848 vnc_write_u8(vs, 0);
849 saved_offset = vs->output.offset;
850 vnc_write_u16(vs, 0);
851
aliguori6cec5482009-01-15 22:17:38 +0000852 for (y = 0; y < vs->serverds.height; y++) {
bellard24236862006-04-30 21:28:36 +0000853 int x;
854 int last_x = -1;
aliguori6cec5482009-01-15 22:17:38 +0000855 for (x = 0; x < vs->serverds.width / 16; x++) {
bellard99589bd2006-06-13 16:35:24 +0000856 if (vnc_get_bit(vs->dirty_row[y], x)) {
bellard24236862006-04-30 21:28:36 +0000857 if (last_x == -1) {
858 last_x = x;
859 }
bellard99589bd2006-06-13 16:35:24 +0000860 vnc_clear_bit(vs->dirty_row[y], x);
bellard24236862006-04-30 21:28:36 +0000861 } else {
862 if (last_x != -1) {
863 int h = find_dirty_height(vs, y, last_x, x);
864 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
865 n_rectangles++;
866 }
867 last_x = -1;
868 }
869 }
870 if (last_x != -1) {
871 int h = find_dirty_height(vs, y, last_x, x);
872 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
873 n_rectangles++;
874 }
875 }
876 vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
877 vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
878 vnc_flush(vs);
879
880 }
bellard24236862006-04-30 21:28:36 +0000881
balroga0ecfb72008-01-13 23:51:53 +0000882 if (vs->csock != -1) {
883 qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
bellard24236862006-04-30 21:28:36 +0000884 }
bellard24236862006-04-30 21:28:36 +0000885
bellard24236862006-04-30 21:28:36 +0000886}
887
malc429a8ed2008-12-01 20:57:48 +0000888/* audio */
889static void audio_capture_notify(void *opaque, audcnotification_e cmd)
890{
891 VncState *vs = opaque;
892
893 switch (cmd) {
894 case AUD_CNOTIFY_DISABLE:
895 vnc_write_u8(vs, 255);
896 vnc_write_u8(vs, 1);
897 vnc_write_u16(vs, 0);
898 vnc_flush(vs);
899 break;
900
901 case AUD_CNOTIFY_ENABLE:
902 vnc_write_u8(vs, 255);
903 vnc_write_u8(vs, 1);
904 vnc_write_u16(vs, 1);
905 vnc_flush(vs);
906 break;
907 }
908}
909
910static void audio_capture_destroy(void *opaque)
911{
912}
913
914static void audio_capture(void *opaque, void *buf, int size)
915{
916 VncState *vs = opaque;
917
918 vnc_write_u8(vs, 255);
919 vnc_write_u8(vs, 1);
920 vnc_write_u16(vs, 2);
921 vnc_write_u32(vs, size);
922 vnc_write(vs, buf, size);
923 vnc_flush(vs);
924}
925
926static void audio_add(VncState *vs)
927{
aliguori376253e2009-03-05 23:01:23 +0000928 Monitor *mon = cur_mon;
malc429a8ed2008-12-01 20:57:48 +0000929 struct audio_capture_ops ops;
930
931 if (vs->audio_cap) {
aliguori376253e2009-03-05 23:01:23 +0000932 monitor_printf(mon, "audio already running\n");
malc429a8ed2008-12-01 20:57:48 +0000933 return;
934 }
935
936 ops.notify = audio_capture_notify;
937 ops.destroy = audio_capture_destroy;
938 ops.capture = audio_capture;
939
940 vs->audio_cap = AUD_add_capture(NULL, &vs->as, &ops, vs);
941 if (!vs->audio_cap) {
aliguori376253e2009-03-05 23:01:23 +0000942 monitor_printf(mon, "Failed to add audio capture\n");
malc429a8ed2008-12-01 20:57:48 +0000943 }
944}
945
946static void audio_del(VncState *vs)
947{
948 if (vs->audio_cap) {
949 AUD_del_capture(vs->audio_cap, vs);
950 vs->audio_cap = NULL;
951 }
952}
953
bellard6ca957f2006-04-30 22:53:25 +0000954static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
bellard24236862006-04-30 21:28:36 +0000955{
956 if (ret == 0 || ret == -1) {
balrogea01e5f2008-04-24 23:40:55 +0000957 if (ret == -1) {
958 switch (last_errno) {
959 case EINTR:
960 case EAGAIN:
961#ifdef _WIN32
962 case WSAEWOULDBLOCK:
963#endif
964 return 0;
965 default:
966 break;
967 }
968 }
bellard24236862006-04-30 21:28:36 +0000969
ths8d5d2d42007-08-25 01:37:51 +0000970 VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0);
bellard24236862006-04-30 21:28:36 +0000971 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
bellard6ca957f2006-04-30 22:53:25 +0000972 closesocket(vs->csock);
aliguori753b4052009-02-16 14:59:30 +0000973 qemu_del_timer(vs->timer);
974 qemu_free_timer(vs->timer);
975 if (vs->input.buffer) qemu_free(vs->input.buffer);
976 if (vs->output.buffer) qemu_free(vs->output.buffer);
blueswir1eb38c522008-09-06 17:47:39 +0000977#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000978 if (vs->tls_session) {
979 gnutls_deinit(vs->tls_session);
980 vs->tls_session = NULL;
981 }
ths8d5d2d42007-08-25 01:37:51 +0000982#endif /* CONFIG_VNC_TLS */
malc429a8ed2008-12-01 20:57:48 +0000983 audio_del(vs);
aliguori753b4052009-02-16 14:59:30 +0000984
985 VncState *p, *parent = NULL;
986 for (p = vs->vd->clients; p != NULL; p = p->next) {
987 if (p == vs) {
988 if (parent)
989 parent->next = p->next;
990 else
991 vs->vd->clients = p->next;
992 break;
993 }
994 parent = p;
995 }
996 if (!vs->vd->clients)
997 dcl->idle = 1;
998
999 qemu_free(vs->old_data);
1000 qemu_free(vs);
1001
bellard24236862006-04-30 21:28:36 +00001002 return 0;
1003 }
1004 return ret;
1005}
1006
1007static void vnc_client_error(VncState *vs)
1008{
bellard6ca957f2006-04-30 22:53:25 +00001009 vnc_client_io_error(vs, -1, EINVAL);
bellard24236862006-04-30 21:28:36 +00001010}
1011
1012static void vnc_client_write(void *opaque)
1013{
bellardceb5caa2006-05-03 21:18:59 +00001014 long ret;
bellard24236862006-04-30 21:28:36 +00001015 VncState *vs = opaque;
1016
blueswir1eb38c522008-09-06 17:47:39 +00001017#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00001018 if (vs->tls_session) {
1019 ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset);
1020 if (ret < 0) {
1021 if (ret == GNUTLS_E_AGAIN)
1022 errno = EAGAIN;
1023 else
1024 errno = EIO;
1025 ret = -1;
1026 }
1027 } else
1028#endif /* CONFIG_VNC_TLS */
1029 ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
bellard6ca957f2006-04-30 22:53:25 +00001030 ret = vnc_client_io_error(vs, ret, socket_error());
bellard24236862006-04-30 21:28:36 +00001031 if (!ret)
1032 return;
1033
1034 memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
1035 vs->output.offset -= ret;
1036
1037 if (vs->output.offset == 0) {
1038 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
1039 }
1040}
1041
1042static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
1043{
1044 vs->read_handler = func;
1045 vs->read_handler_expect = expecting;
1046}
1047
1048static void vnc_client_read(void *opaque)
1049{
1050 VncState *vs = opaque;
bellardceb5caa2006-05-03 21:18:59 +00001051 long ret;
bellard24236862006-04-30 21:28:36 +00001052
1053 buffer_reserve(&vs->input, 4096);
1054
blueswir1eb38c522008-09-06 17:47:39 +00001055#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00001056 if (vs->tls_session) {
1057 ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096);
1058 if (ret < 0) {
1059 if (ret == GNUTLS_E_AGAIN)
1060 errno = EAGAIN;
1061 else
1062 errno = EIO;
1063 ret = -1;
1064 }
1065 } else
1066#endif /* CONFIG_VNC_TLS */
1067 ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
bellard6ca957f2006-04-30 22:53:25 +00001068 ret = vnc_client_io_error(vs, ret, socket_error());
bellard24236862006-04-30 21:28:36 +00001069 if (!ret)
1070 return;
1071
1072 vs->input.offset += ret;
1073
1074 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
1075 size_t len = vs->read_handler_expect;
1076 int ret;
1077
1078 ret = vs->read_handler(vs, vs->input.buffer, len);
1079 if (vs->csock == -1)
1080 return;
1081
1082 if (!ret) {
1083 memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
1084 vs->input.offset -= len;
1085 } else {
1086 vs->read_handler_expect = ret;
1087 }
1088 }
1089}
1090
1091static void vnc_write(VncState *vs, const void *data, size_t len)
1092{
1093 buffer_reserve(&vs->output, len);
1094
1095 if (buffer_empty(&vs->output)) {
1096 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
1097 }
1098
1099 buffer_append(&vs->output, data, len);
1100}
1101
1102static void vnc_write_s32(VncState *vs, int32_t value)
1103{
1104 vnc_write_u32(vs, *(uint32_t *)&value);
1105}
1106
1107static void vnc_write_u32(VncState *vs, uint32_t value)
1108{
1109 uint8_t buf[4];
1110
1111 buf[0] = (value >> 24) & 0xFF;
1112 buf[1] = (value >> 16) & 0xFF;
1113 buf[2] = (value >> 8) & 0xFF;
1114 buf[3] = value & 0xFF;
1115
1116 vnc_write(vs, buf, 4);
1117}
1118
1119static void vnc_write_u16(VncState *vs, uint16_t value)
1120{
bellard64f5a132006-08-24 20:36:44 +00001121 uint8_t buf[2];
bellard24236862006-04-30 21:28:36 +00001122
1123 buf[0] = (value >> 8) & 0xFF;
1124 buf[1] = value & 0xFF;
1125
1126 vnc_write(vs, buf, 2);
1127}
1128
1129static void vnc_write_u8(VncState *vs, uint8_t value)
1130{
1131 vnc_write(vs, (char *)&value, 1);
1132}
1133
1134static void vnc_flush(VncState *vs)
1135{
1136 if (vs->output.offset)
1137 vnc_client_write(vs);
1138}
1139
bellard64f5a132006-08-24 20:36:44 +00001140static uint8_t read_u8(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001141{
1142 return data[offset];
1143}
1144
bellard64f5a132006-08-24 20:36:44 +00001145static uint16_t read_u16(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001146{
1147 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
1148}
1149
bellard64f5a132006-08-24 20:36:44 +00001150static int32_t read_s32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001151{
1152 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
1153 (data[offset + 2] << 8) | data[offset + 3]);
1154}
1155
bellard64f5a132006-08-24 20:36:44 +00001156static uint32_t read_u32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001157{
1158 return ((data[offset] << 24) | (data[offset + 1] << 16) |
1159 (data[offset + 2] << 8) | data[offset + 3]);
1160}
1161
blueswir1eb38c522008-09-06 17:47:39 +00001162#ifdef CONFIG_VNC_TLS
pbrook9596ebb2007-11-18 01:44:38 +00001163static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
1164 const void *data,
1165 size_t len) {
ths8d5d2d42007-08-25 01:37:51 +00001166 struct VncState *vs = (struct VncState *)transport;
1167 int ret;
1168
1169 retry:
1170 ret = send(vs->csock, data, len, 0);
1171 if (ret < 0) {
1172 if (errno == EINTR)
1173 goto retry;
1174 return -1;
1175 }
1176 return ret;
1177}
1178
1179
pbrook9596ebb2007-11-18 01:44:38 +00001180static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
1181 void *data,
1182 size_t len) {
ths8d5d2d42007-08-25 01:37:51 +00001183 struct VncState *vs = (struct VncState *)transport;
1184 int ret;
1185
1186 retry:
1187 ret = recv(vs->csock, data, len, 0);
1188 if (ret < 0) {
1189 if (errno == EINTR)
1190 goto retry;
1191 return -1;
1192 }
1193 return ret;
1194}
1195#endif /* CONFIG_VNC_TLS */
1196
ths60fe76f2007-12-16 03:02:09 +00001197static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
bellard24236862006-04-30 21:28:36 +00001198{
1199}
1200
bellard564c3372007-02-05 20:14:10 +00001201static void check_pointer_type_change(VncState *vs, int absolute)
1202{
aliguori29fa4ed2009-02-02 15:58:29 +00001203 if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
bellard564c3372007-02-05 20:14:10 +00001204 vnc_write_u8(vs, 0);
1205 vnc_write_u8(vs, 0);
1206 vnc_write_u16(vs, 1);
1207 vnc_framebuffer_update(vs, absolute, 0,
aliguori29fa4ed2009-02-02 15:58:29 +00001208 ds_get_width(vs->ds), ds_get_height(vs->ds),
1209 VNC_ENCODING_POINTER_TYPE_CHANGE);
bellard564c3372007-02-05 20:14:10 +00001210 vnc_flush(vs);
1211 }
1212 vs->absolute = absolute;
1213}
1214
bellard24236862006-04-30 21:28:36 +00001215static void pointer_event(VncState *vs, int button_mask, int x, int y)
1216{
1217 int buttons = 0;
1218 int dz = 0;
1219
1220 if (button_mask & 0x01)
1221 buttons |= MOUSE_EVENT_LBUTTON;
1222 if (button_mask & 0x02)
1223 buttons |= MOUSE_EVENT_MBUTTON;
1224 if (button_mask & 0x04)
1225 buttons |= MOUSE_EVENT_RBUTTON;
1226 if (button_mask & 0x08)
1227 dz = -1;
1228 if (button_mask & 0x10)
1229 dz = 1;
bellard564c3372007-02-05 20:14:10 +00001230
1231 if (vs->absolute) {
aliguori0e1f5a02008-11-24 19:29:13 +00001232 kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
1233 y * 0x7FFF / (ds_get_height(vs->ds) - 1),
bellard24236862006-04-30 21:28:36 +00001234 dz, buttons);
aliguori29fa4ed2009-02-02 15:58:29 +00001235 } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
bellard564c3372007-02-05 20:14:10 +00001236 x -= 0x7FFF;
1237 y -= 0x7FFF;
1238
1239 kbd_mouse_event(x, y, dz, buttons);
bellard24236862006-04-30 21:28:36 +00001240 } else {
bellard564c3372007-02-05 20:14:10 +00001241 if (vs->last_x != -1)
1242 kbd_mouse_event(x - vs->last_x,
1243 y - vs->last_y,
1244 dz, buttons);
1245 vs->last_x = x;
1246 vs->last_y = y;
bellard24236862006-04-30 21:28:36 +00001247 }
bellard564c3372007-02-05 20:14:10 +00001248
1249 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001250}
1251
bellard64f5a132006-08-24 20:36:44 +00001252static void reset_keys(VncState *vs)
1253{
1254 int i;
1255 for(i = 0; i < 256; i++) {
1256 if (vs->modifiers_state[i]) {
1257 if (i & 0x80)
1258 kbd_put_keycode(0xe0);
1259 kbd_put_keycode(i | 0x80);
1260 vs->modifiers_state[i] = 0;
1261 }
1262 }
1263}
1264
balroga528b802007-10-30 22:38:53 +00001265static void press_key(VncState *vs, int keysym)
1266{
aliguori753b4052009-02-16 14:59:30 +00001267 kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f);
1268 kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80);
balroga528b802007-10-30 22:38:53 +00001269}
1270
aliguori9ca313a2008-08-23 23:27:37 +00001271static void do_key_event(VncState *vs, int down, int keycode, int sym)
bellard24236862006-04-30 21:28:36 +00001272{
bellard64f5a132006-08-24 20:36:44 +00001273 /* QEMU console switch */
1274 switch(keycode) {
1275 case 0x2a: /* Left Shift */
1276 case 0x36: /* Right Shift */
1277 case 0x1d: /* Left CTRL */
1278 case 0x9d: /* Right CTRL */
1279 case 0x38: /* Left ALT */
1280 case 0xb8: /* Right ALT */
1281 if (down)
1282 vs->modifiers_state[keycode] = 1;
1283 else
1284 vs->modifiers_state[keycode] = 0;
1285 break;
ths5fafdf22007-09-16 21:08:06 +00001286 case 0x02 ... 0x0a: /* '1' to '9' keys */
bellard64f5a132006-08-24 20:36:44 +00001287 if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1288 /* Reset the modifiers sent to the current console */
1289 reset_keys(vs);
1290 console_select(keycode - 0x02);
1291 return;
1292 }
1293 break;
balrog4d3b6f62008-02-10 16:33:14 +00001294 case 0x3a: /* CapsLock */
balroga528b802007-10-30 22:38:53 +00001295 case 0x45: /* NumLock */
1296 if (!down)
1297 vs->modifiers_state[keycode] ^= 1;
1298 break;
1299 }
1300
aliguori753b4052009-02-16 14:59:30 +00001301 if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
balroga528b802007-10-30 22:38:53 +00001302 /* If the numlock state needs to change then simulate an additional
1303 keypress before sending this one. This will happen if the user
1304 toggles numlock away from the VNC window.
1305 */
aliguori753b4052009-02-16 14:59:30 +00001306 if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
balroga528b802007-10-30 22:38:53 +00001307 if (!vs->modifiers_state[0x45]) {
1308 vs->modifiers_state[0x45] = 1;
1309 press_key(vs, 0xff7f);
1310 }
1311 } else {
1312 if (vs->modifiers_state[0x45]) {
1313 vs->modifiers_state[0x45] = 0;
1314 press_key(vs, 0xff7f);
1315 }
1316 }
bellard64f5a132006-08-24 20:36:44 +00001317 }
bellard24236862006-04-30 21:28:36 +00001318
bellard64f5a132006-08-24 20:36:44 +00001319 if (is_graphic_console()) {
1320 if (keycode & 0x80)
1321 kbd_put_keycode(0xe0);
1322 if (down)
1323 kbd_put_keycode(keycode & 0x7f);
1324 else
1325 kbd_put_keycode(keycode | 0x80);
1326 } else {
1327 /* QEMU console emulation */
1328 if (down) {
1329 switch (keycode) {
1330 case 0x2a: /* Left Shift */
1331 case 0x36: /* Right Shift */
1332 case 0x1d: /* Left CTRL */
1333 case 0x9d: /* Right CTRL */
1334 case 0x38: /* Left ALT */
1335 case 0xb8: /* Right ALT */
1336 break;
1337 case 0xc8:
1338 kbd_put_keysym(QEMU_KEY_UP);
1339 break;
1340 case 0xd0:
1341 kbd_put_keysym(QEMU_KEY_DOWN);
1342 break;
1343 case 0xcb:
1344 kbd_put_keysym(QEMU_KEY_LEFT);
1345 break;
1346 case 0xcd:
1347 kbd_put_keysym(QEMU_KEY_RIGHT);
1348 break;
1349 case 0xd3:
1350 kbd_put_keysym(QEMU_KEY_DELETE);
1351 break;
1352 case 0xc7:
1353 kbd_put_keysym(QEMU_KEY_HOME);
1354 break;
1355 case 0xcf:
1356 kbd_put_keysym(QEMU_KEY_END);
1357 break;
1358 case 0xc9:
1359 kbd_put_keysym(QEMU_KEY_PAGEUP);
1360 break;
1361 case 0xd1:
1362 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1363 break;
1364 default:
1365 kbd_put_keysym(sym);
1366 break;
1367 }
1368 }
1369 }
bellard24236862006-04-30 21:28:36 +00001370}
1371
bellardbdbd7672006-05-01 21:44:22 +00001372static void key_event(VncState *vs, int down, uint32_t sym)
1373{
aliguori9ca313a2008-08-23 23:27:37 +00001374 int keycode;
1375
balroga528b802007-10-30 22:38:53 +00001376 if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
bellardbdbd7672006-05-01 21:44:22 +00001377 sym = sym - 'A' + 'a';
aliguori9ca313a2008-08-23 23:27:37 +00001378
aliguori753b4052009-02-16 14:59:30 +00001379 keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF);
aliguori9ca313a2008-08-23 23:27:37 +00001380 do_key_event(vs, down, keycode, sym);
1381}
1382
1383static void ext_key_event(VncState *vs, int down,
1384 uint32_t sym, uint16_t keycode)
1385{
1386 /* if the user specifies a keyboard layout, always use it */
1387 if (keyboard_layout)
1388 key_event(vs, down, sym);
1389 else
1390 do_key_event(vs, down, keycode, sym);
bellardbdbd7672006-05-01 21:44:22 +00001391}
1392
bellard24236862006-04-30 21:28:36 +00001393static void framebuffer_update_request(VncState *vs, int incremental,
1394 int x_position, int y_position,
1395 int w, int h)
1396{
aliguori0e1f5a02008-11-24 19:29:13 +00001397 if (x_position > ds_get_width(vs->ds))
1398 x_position = ds_get_width(vs->ds);
1399 if (y_position > ds_get_height(vs->ds))
1400 y_position = ds_get_height(vs->ds);
1401 if (x_position + w >= ds_get_width(vs->ds))
1402 w = ds_get_width(vs->ds) - x_position;
1403 if (y_position + h >= ds_get_height(vs->ds))
1404 h = ds_get_height(vs->ds) - y_position;
thscf2d3852007-04-29 01:53:20 +00001405
bellard24236862006-04-30 21:28:36 +00001406 int i;
1407 vs->need_update = 1;
1408 if (!incremental) {
aliguori0e1f5a02008-11-24 19:29:13 +00001409 char *old_row = vs->old_data + y_position * ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +00001410
1411 for (i = 0; i < h; i++) {
ths5fafdf22007-09-16 21:08:06 +00001412 vnc_set_bits(vs->dirty_row[y_position + i],
aliguori0e1f5a02008-11-24 19:29:13 +00001413 (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
aliguori6cec5482009-01-15 22:17:38 +00001414 memset(old_row, 42, ds_get_width(vs->ds) * ds_get_bytes_per_pixel(vs->ds));
aliguori0e1f5a02008-11-24 19:29:13 +00001415 old_row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +00001416 }
1417 }
1418}
1419
aliguori9ca313a2008-08-23 23:27:37 +00001420static void send_ext_key_event_ack(VncState *vs)
1421{
1422 vnc_write_u8(vs, 0);
1423 vnc_write_u8(vs, 0);
1424 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001425 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1426 VNC_ENCODING_EXT_KEY_EVENT);
aliguori9ca313a2008-08-23 23:27:37 +00001427 vnc_flush(vs);
1428}
1429
malc429a8ed2008-12-01 20:57:48 +00001430static void send_ext_audio_ack(VncState *vs)
1431{
1432 vnc_write_u8(vs, 0);
1433 vnc_write_u8(vs, 0);
1434 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001435 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1436 VNC_ENCODING_AUDIO);
malc429a8ed2008-12-01 20:57:48 +00001437 vnc_flush(vs);
1438}
1439
bellard24236862006-04-30 21:28:36 +00001440static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1441{
1442 int i;
aliguori29fa4ed2009-02-02 15:58:29 +00001443 unsigned int enc = 0;
bellard24236862006-04-30 21:28:36 +00001444
aliguori059cef42009-02-02 15:58:54 +00001445 vnc_zlib_init(vs);
aliguori29fa4ed2009-02-02 15:58:29 +00001446 vs->features = 0;
aliguorifb437312009-02-02 15:58:43 +00001447 vs->vnc_encoding = 0;
1448 vs->tight_compression = 9;
1449 vs->tight_quality = 9;
bellard564c3372007-02-05 20:14:10 +00001450 vs->absolute = -1;
bellard24236862006-04-30 21:28:36 +00001451
1452 for (i = n_encodings - 1; i >= 0; i--) {
aliguori29fa4ed2009-02-02 15:58:29 +00001453 enc = encodings[i];
1454 switch (enc) {
1455 case VNC_ENCODING_RAW:
aliguorifb437312009-02-02 15:58:43 +00001456 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001457 break;
1458 case VNC_ENCODING_COPYRECT:
aliguori753b4052009-02-16 14:59:30 +00001459 vs->features |= VNC_FEATURE_COPYRECT_MASK;
aliguori29fa4ed2009-02-02 15:58:29 +00001460 break;
1461 case VNC_ENCODING_HEXTILE:
1462 vs->features |= VNC_FEATURE_HEXTILE_MASK;
aliguorifb437312009-02-02 15:58:43 +00001463 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001464 break;
aliguori059cef42009-02-02 15:58:54 +00001465 case VNC_ENCODING_ZLIB:
1466 vs->features |= VNC_FEATURE_ZLIB_MASK;
1467 vs->vnc_encoding = enc;
1468 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001469 case VNC_ENCODING_DESKTOPRESIZE:
1470 vs->features |= VNC_FEATURE_RESIZE_MASK;
1471 break;
1472 case VNC_ENCODING_POINTER_TYPE_CHANGE:
1473 vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
1474 break;
1475 case VNC_ENCODING_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00001476 send_ext_key_event_ack(vs);
1477 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001478 case VNC_ENCODING_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00001479 send_ext_audio_ack(vs);
1480 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001481 case VNC_ENCODING_WMVi:
1482 vs->features |= VNC_FEATURE_WMVI_MASK;
aliguorica4cca42008-09-15 16:05:16 +00001483 break;
aliguorifb437312009-02-02 15:58:43 +00001484 case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
1485 vs->tight_compression = (enc & 0x0F);
1486 break;
1487 case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
1488 vs->tight_quality = (enc & 0x0F);
1489 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001490 default:
1491 VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
1492 break;
1493 }
bellard24236862006-04-30 21:28:36 +00001494 }
bellard564c3372007-02-05 20:14:10 +00001495
1496 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001497}
1498
aliguori6cec5482009-01-15 22:17:38 +00001499static void set_pixel_conversion(VncState *vs)
1500{
1501 if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
1502 (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) &&
1503 !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
1504 vs->write_pixels = vnc_write_pixels_copy;
1505 switch (vs->ds->surface->pf.bits_per_pixel) {
1506 case 8:
1507 vs->send_hextile_tile = send_hextile_tile_8;
1508 break;
1509 case 16:
1510 vs->send_hextile_tile = send_hextile_tile_16;
1511 break;
1512 case 32:
1513 vs->send_hextile_tile = send_hextile_tile_32;
1514 break;
1515 }
1516 } else {
1517 vs->write_pixels = vnc_write_pixels_generic;
1518 switch (vs->ds->surface->pf.bits_per_pixel) {
1519 case 8:
1520 vs->send_hextile_tile = send_hextile_tile_generic_8;
1521 break;
1522 case 16:
1523 vs->send_hextile_tile = send_hextile_tile_generic_16;
1524 break;
1525 case 32:
1526 vs->send_hextile_tile = send_hextile_tile_generic_32;
1527 break;
1528 }
1529 }
1530}
1531
bellard24236862006-04-30 21:28:36 +00001532static void set_pixel_format(VncState *vs,
1533 int bits_per_pixel, int depth,
1534 int big_endian_flag, int true_color_flag,
1535 int red_max, int green_max, int blue_max,
1536 int red_shift, int green_shift, int blue_shift)
1537{
bellard35127792006-05-14 18:11:49 +00001538 if (!true_color_flag) {
bellard24236862006-04-30 21:28:36 +00001539 vnc_client_error(vs);
bellard35127792006-05-14 18:11:49 +00001540 return;
1541 }
aliguori7eac3a82008-09-15 16:03:41 +00001542
aliguori6cec5482009-01-15 22:17:38 +00001543 vs->clientds = vs->serverds;
1544 vs->clientds.pf.rmax = red_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001545 count_bits(vs->clientds.pf.rbits, red_max);
aliguori6cec5482009-01-15 22:17:38 +00001546 vs->clientds.pf.rshift = red_shift;
1547 vs->clientds.pf.rmask = red_max << red_shift;
1548 vs->clientds.pf.gmax = green_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001549 count_bits(vs->clientds.pf.gbits, green_max);
aliguori6cec5482009-01-15 22:17:38 +00001550 vs->clientds.pf.gshift = green_shift;
1551 vs->clientds.pf.gmask = green_max << green_shift;
1552 vs->clientds.pf.bmax = blue_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001553 count_bits(vs->clientds.pf.bbits, blue_max);
aliguori6cec5482009-01-15 22:17:38 +00001554 vs->clientds.pf.bshift = blue_shift;
1555 vs->clientds.pf.bmask = blue_max << blue_shift;
1556 vs->clientds.pf.bits_per_pixel = bits_per_pixel;
1557 vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
1558 vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
1559 vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
bellard24236862006-04-30 21:28:36 +00001560
aliguori6cec5482009-01-15 22:17:38 +00001561 set_pixel_conversion(vs);
bellard24236862006-04-30 21:28:36 +00001562
1563 vga_hw_invalidate();
1564 vga_hw_update();
1565}
1566
aliguorica4cca42008-09-15 16:05:16 +00001567static void pixel_format_message (VncState *vs) {
1568 char pad[3] = { 0, 0, 0 };
1569
aliguori6cec5482009-01-15 22:17:38 +00001570 vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
1571 vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
aliguorica4cca42008-09-15 16:05:16 +00001572
1573#ifdef WORDS_BIGENDIAN
1574 vnc_write_u8(vs, 1); /* big-endian-flag */
1575#else
1576 vnc_write_u8(vs, 0); /* big-endian-flag */
1577#endif
1578 vnc_write_u8(vs, 1); /* true-color-flag */
aliguori6cec5482009-01-15 22:17:38 +00001579 vnc_write_u16(vs, vs->ds->surface->pf.rmax); /* red-max */
1580 vnc_write_u16(vs, vs->ds->surface->pf.gmax); /* green-max */
1581 vnc_write_u16(vs, vs->ds->surface->pf.bmax); /* blue-max */
1582 vnc_write_u8(vs, vs->ds->surface->pf.rshift); /* red-shift */
1583 vnc_write_u8(vs, vs->ds->surface->pf.gshift); /* green-shift */
1584 vnc_write_u8(vs, vs->ds->surface->pf.bshift); /* blue-shift */
1585 if (vs->ds->surface->pf.bits_per_pixel == 32)
aliguorica4cca42008-09-15 16:05:16 +00001586 vs->send_hextile_tile = send_hextile_tile_32;
aliguori6cec5482009-01-15 22:17:38 +00001587 else if (vs->ds->surface->pf.bits_per_pixel == 16)
aliguorica4cca42008-09-15 16:05:16 +00001588 vs->send_hextile_tile = send_hextile_tile_16;
aliguori6cec5482009-01-15 22:17:38 +00001589 else if (vs->ds->surface->pf.bits_per_pixel == 8)
aliguorica4cca42008-09-15 16:05:16 +00001590 vs->send_hextile_tile = send_hextile_tile_8;
aliguori6cec5482009-01-15 22:17:38 +00001591 vs->clientds = *(vs->ds->surface);
1592 vs->clientds.flags |= ~QEMU_ALLOCATED_FLAG;
aliguorica4cca42008-09-15 16:05:16 +00001593 vs->write_pixels = vnc_write_pixels_copy;
1594
1595 vnc_write(vs, pad, 3); /* padding */
1596}
1597
aliguori7d957bd2009-01-15 22:14:11 +00001598static void vnc_dpy_setdata(DisplayState *ds)
1599{
1600 /* We don't have to do anything */
1601}
1602
aliguori753b4052009-02-16 14:59:30 +00001603static void vnc_colordepth(VncState *vs)
aliguori7eac3a82008-09-15 16:03:41 +00001604{
aliguori753b4052009-02-16 14:59:30 +00001605 if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
aliguorica4cca42008-09-15 16:05:16 +00001606 /* Sending a WMVi message to notify the client*/
1607 vnc_write_u8(vs, 0); /* msg id */
1608 vnc_write_u8(vs, 0);
1609 vnc_write_u16(vs, 1); /* number of rects */
aliguori753b4052009-02-16 14:59:30 +00001610 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds),
1611 ds_get_height(vs->ds), VNC_ENCODING_WMVi);
aliguorica4cca42008-09-15 16:05:16 +00001612 pixel_format_message(vs);
1613 vnc_flush(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001614 } else {
aliguori6cec5482009-01-15 22:17:38 +00001615 set_pixel_conversion(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001616 }
1617}
1618
ths60fe76f2007-12-16 03:02:09 +00001619static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001620{
1621 int i;
1622 uint16_t limit;
1623
1624 switch (data[0]) {
1625 case 0:
1626 if (len == 1)
1627 return 20;
1628
1629 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
1630 read_u8(data, 6), read_u8(data, 7),
1631 read_u16(data, 8), read_u16(data, 10),
1632 read_u16(data, 12), read_u8(data, 14),
1633 read_u8(data, 15), read_u8(data, 16));
1634 break;
1635 case 2:
1636 if (len == 1)
1637 return 4;
1638
aliguori69dd5c92008-12-22 21:06:23 +00001639 if (len == 4) {
1640 limit = read_u16(data, 2);
1641 if (limit > 0)
1642 return 4 + (limit * 4);
1643 } else
1644 limit = read_u16(data, 2);
bellard24236862006-04-30 21:28:36 +00001645
bellard24236862006-04-30 21:28:36 +00001646 for (i = 0; i < limit; i++) {
1647 int32_t val = read_s32(data, 4 + (i * 4));
1648 memcpy(data + 4 + (i * 4), &val, sizeof(val));
1649 }
1650
1651 set_encodings(vs, (int32_t *)(data + 4), limit);
1652 break;
1653 case 3:
1654 if (len == 1)
1655 return 10;
1656
1657 framebuffer_update_request(vs,
1658 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
1659 read_u16(data, 6), read_u16(data, 8));
1660 break;
1661 case 4:
1662 if (len == 1)
1663 return 8;
1664
1665 key_event(vs, read_u8(data, 1), read_u32(data, 4));
1666 break;
1667 case 5:
1668 if (len == 1)
1669 return 6;
1670
1671 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
1672 break;
1673 case 6:
1674 if (len == 1)
1675 return 8;
1676
thsbaa76662007-09-13 12:41:42 +00001677 if (len == 8) {
1678 uint32_t dlen = read_u32(data, 4);
1679 if (dlen > 0)
1680 return 8 + dlen;
1681 }
bellard24236862006-04-30 21:28:36 +00001682
1683 client_cut_text(vs, read_u32(data, 4), data + 8);
1684 break;
aliguori9ca313a2008-08-23 23:27:37 +00001685 case 255:
1686 if (len == 1)
1687 return 2;
1688
1689 switch (read_u8(data, 1)) {
1690 case 0:
1691 if (len == 2)
1692 return 12;
1693
1694 ext_key_event(vs, read_u16(data, 2),
1695 read_u32(data, 4), read_u32(data, 8));
1696 break;
malc429a8ed2008-12-01 20:57:48 +00001697 case 1:
1698 if (len == 2)
1699 return 4;
1700
1701 switch (read_u16 (data, 2)) {
1702 case 0:
1703 audio_add(vs);
1704 break;
1705 case 1:
1706 audio_del(vs);
1707 break;
1708 case 2:
1709 if (len == 4)
1710 return 10;
1711 switch (read_u8(data, 4)) {
1712 case 0: vs->as.fmt = AUD_FMT_U8; break;
1713 case 1: vs->as.fmt = AUD_FMT_S8; break;
1714 case 2: vs->as.fmt = AUD_FMT_U16; break;
1715 case 3: vs->as.fmt = AUD_FMT_S16; break;
1716 case 4: vs->as.fmt = AUD_FMT_U32; break;
1717 case 5: vs->as.fmt = AUD_FMT_S32; break;
1718 default:
1719 printf("Invalid audio format %d\n", read_u8(data, 4));
1720 vnc_client_error(vs);
1721 break;
1722 }
1723 vs->as.nchannels = read_u8(data, 5);
1724 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
1725 printf("Invalid audio channel coount %d\n",
1726 read_u8(data, 5));
1727 vnc_client_error(vs);
1728 break;
1729 }
1730 vs->as.freq = read_u32(data, 6);
1731 break;
1732 default:
1733 printf ("Invalid audio message %d\n", read_u8(data, 4));
1734 vnc_client_error(vs);
1735 break;
1736 }
1737 break;
1738
aliguori9ca313a2008-08-23 23:27:37 +00001739 default:
1740 printf("Msg: %d\n", read_u16(data, 0));
1741 vnc_client_error(vs);
1742 break;
1743 }
1744 break;
bellard24236862006-04-30 21:28:36 +00001745 default:
1746 printf("Msg: %d\n", data[0]);
1747 vnc_client_error(vs);
1748 break;
1749 }
ths5fafdf22007-09-16 21:08:06 +00001750
bellard24236862006-04-30 21:28:36 +00001751 vnc_read_when(vs, protocol_client_msg, 1);
1752 return 0;
1753}
1754
ths60fe76f2007-12-16 03:02:09 +00001755static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001756{
thsc35734b2007-03-19 15:17:08 +00001757 char buf[1024];
1758 int size;
bellard24236862006-04-30 21:28:36 +00001759
aliguori0e1f5a02008-11-24 19:29:13 +00001760 vnc_write_u16(vs, ds_get_width(vs->ds));
1761 vnc_write_u16(vs, ds_get_height(vs->ds));
bellard24236862006-04-30 21:28:36 +00001762
aliguorica4cca42008-09-15 16:05:16 +00001763 pixel_format_message(vs);
bellard24236862006-04-30 21:28:36 +00001764
thsc35734b2007-03-19 15:17:08 +00001765 if (qemu_name)
1766 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
1767 else
1768 size = snprintf(buf, sizeof(buf), "QEMU");
1769
1770 vnc_write_u32(vs, size);
1771 vnc_write(vs, buf, size);
bellard24236862006-04-30 21:28:36 +00001772 vnc_flush(vs);
1773
1774 vnc_read_when(vs, protocol_client_msg, 1);
1775
1776 return 0;
1777}
1778
ths70848512007-08-25 01:37:05 +00001779static void make_challenge(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001780{
ths70848512007-08-25 01:37:05 +00001781 int i;
bellard24236862006-04-30 21:28:36 +00001782
ths70848512007-08-25 01:37:05 +00001783 srand(time(NULL)+getpid()+getpid()*987654+rand());
bellard24236862006-04-30 21:28:36 +00001784
ths70848512007-08-25 01:37:05 +00001785 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
1786 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
1787}
1788
ths60fe76f2007-12-16 03:02:09 +00001789static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00001790{
ths60fe76f2007-12-16 03:02:09 +00001791 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
ths70848512007-08-25 01:37:05 +00001792 int i, j, pwlen;
ths60fe76f2007-12-16 03:02:09 +00001793 unsigned char key[8];
ths70848512007-08-25 01:37:05 +00001794
aliguori753b4052009-02-16 14:59:30 +00001795 if (!vs->vd->password || !vs->vd->password[0]) {
ths70848512007-08-25 01:37:05 +00001796 VNC_DEBUG("No password configured on server");
1797 vnc_write_u32(vs, 1); /* Reject auth */
1798 if (vs->minor >= 8) {
1799 static const char err[] = "Authentication failed";
1800 vnc_write_u32(vs, sizeof(err));
1801 vnc_write(vs, err, sizeof(err));
1802 }
1803 vnc_flush(vs);
bellard24236862006-04-30 21:28:36 +00001804 vnc_client_error(vs);
1805 return 0;
1806 }
1807
ths70848512007-08-25 01:37:05 +00001808 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
1809
1810 /* Calculate the expected challenge response */
aliguori753b4052009-02-16 14:59:30 +00001811 pwlen = strlen(vs->vd->password);
ths70848512007-08-25 01:37:05 +00001812 for (i=0; i<sizeof(key); i++)
aliguori753b4052009-02-16 14:59:30 +00001813 key[i] = i<pwlen ? vs->vd->password[i] : 0;
ths70848512007-08-25 01:37:05 +00001814 deskey(key, EN0);
1815 for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
1816 des(response+j, response+j);
1817
1818 /* Compare expected vs actual challenge response */
1819 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
1820 VNC_DEBUG("Client challenge reponse did not match\n");
1821 vnc_write_u32(vs, 1); /* Reject auth */
1822 if (vs->minor >= 8) {
1823 static const char err[] = "Authentication failed";
1824 vnc_write_u32(vs, sizeof(err));
1825 vnc_write(vs, err, sizeof(err));
1826 }
1827 vnc_flush(vs);
1828 vnc_client_error(vs);
1829 } else {
1830 VNC_DEBUG("Accepting VNC challenge response\n");
1831 vnc_write_u32(vs, 0); /* Accept auth */
1832 vnc_flush(vs);
1833
1834 vnc_read_when(vs, protocol_client_init, 1);
1835 }
1836 return 0;
1837}
1838
1839static int start_auth_vnc(VncState *vs)
1840{
1841 make_challenge(vs);
1842 /* Send client a 'random' challenge */
1843 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
bellard24236862006-04-30 21:28:36 +00001844 vnc_flush(vs);
1845
ths70848512007-08-25 01:37:05 +00001846 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
1847 return 0;
1848}
1849
ths8d5d2d42007-08-25 01:37:51 +00001850
blueswir1eb38c522008-09-06 17:47:39 +00001851#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00001852#define DH_BITS 1024
1853static gnutls_dh_params_t dh_params;
1854
1855static int vnc_tls_initialize(void)
1856{
1857 static int tlsinitialized = 0;
1858
1859 if (tlsinitialized)
1860 return 1;
1861
1862 if (gnutls_global_init () < 0)
1863 return 0;
1864
1865 /* XXX ought to re-generate diffie-hellmen params periodically */
1866 if (gnutls_dh_params_init (&dh_params) < 0)
1867 return 0;
1868 if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
1869 return 0;
1870
ths234c9bc2008-09-24 15:17:57 +00001871#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
ths8d5d2d42007-08-25 01:37:51 +00001872 gnutls_global_set_log_level(10);
1873 gnutls_global_set_log_function(vnc_debug_gnutls_log);
1874#endif
1875
1876 tlsinitialized = 1;
1877
1878 return 1;
1879}
1880
1881static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
1882{
1883 gnutls_anon_server_credentials anon_cred;
1884 int ret;
1885
1886 if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
1887 VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
1888 return NULL;
1889 }
1890
1891 gnutls_anon_set_server_dh_params(anon_cred, dh_params);
1892
1893 return anon_cred;
1894}
1895
1896
ths6f430242007-08-25 01:39:57 +00001897static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs)
ths3a702692007-08-25 01:38:36 +00001898{
1899 gnutls_certificate_credentials_t x509_cred;
1900 int ret;
ths6f430242007-08-25 01:39:57 +00001901
aliguori753b4052009-02-16 14:59:30 +00001902 if (!vs->vd->x509cacert) {
ths6f430242007-08-25 01:39:57 +00001903 VNC_DEBUG("No CA x509 certificate specified\n");
1904 return NULL;
1905 }
aliguori753b4052009-02-16 14:59:30 +00001906 if (!vs->vd->x509cert) {
ths6f430242007-08-25 01:39:57 +00001907 VNC_DEBUG("No server x509 certificate specified\n");
1908 return NULL;
1909 }
aliguori753b4052009-02-16 14:59:30 +00001910 if (!vs->vd->x509key) {
ths6f430242007-08-25 01:39:57 +00001911 VNC_DEBUG("No server private key specified\n");
1912 return NULL;
1913 }
ths3a702692007-08-25 01:38:36 +00001914
1915 if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
1916 VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
1917 return NULL;
1918 }
ths6f430242007-08-25 01:39:57 +00001919 if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
aliguori753b4052009-02-16 14:59:30 +00001920 vs->vd->x509cacert,
ths6f430242007-08-25 01:39:57 +00001921 GNUTLS_X509_FMT_PEM)) < 0) {
ths3a702692007-08-25 01:38:36 +00001922 VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
1923 gnutls_certificate_free_credentials(x509_cred);
1924 return NULL;
1925 }
1926
ths6f430242007-08-25 01:39:57 +00001927 if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
aliguori753b4052009-02-16 14:59:30 +00001928 vs->vd->x509cert,
1929 vs->vd->x509key,
ths3a702692007-08-25 01:38:36 +00001930 GNUTLS_X509_FMT_PEM)) < 0) {
1931 VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
1932 gnutls_certificate_free_credentials(x509_cred);
1933 return NULL;
1934 }
1935
aliguori753b4052009-02-16 14:59:30 +00001936 if (vs->vd->x509cacrl) {
ths6f430242007-08-25 01:39:57 +00001937 if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
aliguori753b4052009-02-16 14:59:30 +00001938 vs->vd->x509cacrl,
ths6f430242007-08-25 01:39:57 +00001939 GNUTLS_X509_FMT_PEM)) < 0) {
ths3a702692007-08-25 01:38:36 +00001940 VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
1941 gnutls_certificate_free_credentials(x509_cred);
1942 return NULL;
1943 }
1944 }
1945
1946 gnutls_certificate_set_dh_params (x509_cred, dh_params);
1947
1948 return x509_cred;
1949}
1950
ths469b15c2007-08-25 01:39:10 +00001951static int vnc_validate_certificate(struct VncState *vs)
1952{
1953 int ret;
1954 unsigned int status;
1955 const gnutls_datum_t *certs;
1956 unsigned int nCerts, i;
1957 time_t now;
1958
1959 VNC_DEBUG("Validating client certificate\n");
1960 if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) {
1961 VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
1962 return -1;
1963 }
1964
1965 if ((now = time(NULL)) == ((time_t)-1)) {
1966 return -1;
1967 }
1968
1969 if (status != 0) {
1970 if (status & GNUTLS_CERT_INVALID)
1971 VNC_DEBUG("The certificate is not trusted.\n");
1972
1973 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
1974 VNC_DEBUG("The certificate hasn't got a known issuer.\n");
1975
1976 if (status & GNUTLS_CERT_REVOKED)
1977 VNC_DEBUG("The certificate has been revoked.\n");
1978
1979 if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
1980 VNC_DEBUG("The certificate uses an insecure algorithm\n");
1981
1982 return -1;
1983 } else {
1984 VNC_DEBUG("Certificate is valid!\n");
1985 }
1986
1987 /* Only support x509 for now */
1988 if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509)
1989 return -1;
1990
1991 if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts)))
1992 return -1;
1993
1994 for (i = 0 ; i < nCerts ; i++) {
1995 gnutls_x509_crt_t cert;
1996 VNC_DEBUG ("Checking certificate chain %d\n", i);
1997 if (gnutls_x509_crt_init (&cert) < 0)
1998 return -1;
1999
2000 if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
2001 gnutls_x509_crt_deinit (cert);
2002 return -1;
2003 }
2004
2005 if (gnutls_x509_crt_get_expiration_time (cert) < now) {
2006 VNC_DEBUG("The certificate has expired\n");
2007 gnutls_x509_crt_deinit (cert);
2008 return -1;
2009 }
2010
2011 if (gnutls_x509_crt_get_activation_time (cert) > now) {
2012 VNC_DEBUG("The certificate is not yet activated\n");
2013 gnutls_x509_crt_deinit (cert);
2014 return -1;
2015 }
2016
2017 if (gnutls_x509_crt_get_activation_time (cert) > now) {
2018 VNC_DEBUG("The certificate is not yet activated\n");
2019 gnutls_x509_crt_deinit (cert);
2020 return -1;
2021 }
2022
2023 gnutls_x509_crt_deinit (cert);
2024 }
2025
2026 return 0;
2027}
2028
2029
ths8d5d2d42007-08-25 01:37:51 +00002030static int start_auth_vencrypt_subauth(VncState *vs)
2031{
aliguori753b4052009-02-16 14:59:30 +00002032 switch (vs->vd->subauth) {
ths8d5d2d42007-08-25 01:37:51 +00002033 case VNC_AUTH_VENCRYPT_TLSNONE:
ths3a702692007-08-25 01:38:36 +00002034 case VNC_AUTH_VENCRYPT_X509NONE:
ths8d5d2d42007-08-25 01:37:51 +00002035 VNC_DEBUG("Accept TLS auth none\n");
2036 vnc_write_u32(vs, 0); /* Accept auth completion */
2037 vnc_read_when(vs, protocol_client_init, 1);
2038 break;
2039
2040 case VNC_AUTH_VENCRYPT_TLSVNC:
ths3a702692007-08-25 01:38:36 +00002041 case VNC_AUTH_VENCRYPT_X509VNC:
ths8d5d2d42007-08-25 01:37:51 +00002042 VNC_DEBUG("Start TLS auth VNC\n");
2043 return start_auth_vnc(vs);
2044
2045 default: /* Should not be possible, but just in case */
aliguori753b4052009-02-16 14:59:30 +00002046 VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
ths8d5d2d42007-08-25 01:37:51 +00002047 vnc_write_u8(vs, 1);
2048 if (vs->minor >= 8) {
2049 static const char err[] = "Unsupported authentication type";
2050 vnc_write_u32(vs, sizeof(err));
2051 vnc_write(vs, err, sizeof(err));
2052 }
2053 vnc_client_error(vs);
2054 }
2055
2056 return 0;
2057}
2058
2059static void vnc_handshake_io(void *opaque);
2060
2061static int vnc_continue_handshake(struct VncState *vs) {
2062 int ret;
2063
2064 if ((ret = gnutls_handshake(vs->tls_session)) < 0) {
2065 if (!gnutls_error_is_fatal(ret)) {
2066 VNC_DEBUG("Handshake interrupted (blocking)\n");
2067 if (!gnutls_record_get_direction(vs->tls_session))
2068 qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs);
2069 else
2070 qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs);
2071 return 0;
2072 }
2073 VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
2074 vnc_client_error(vs);
2075 return -1;
2076 }
2077
aliguori753b4052009-02-16 14:59:30 +00002078 if (vs->vd->x509verify) {
ths469b15c2007-08-25 01:39:10 +00002079 if (vnc_validate_certificate(vs) < 0) {
2080 VNC_DEBUG("Client verification failed\n");
2081 vnc_client_error(vs);
2082 return -1;
2083 } else {
2084 VNC_DEBUG("Client verification passed\n");
2085 }
2086 }
2087
ths8d5d2d42007-08-25 01:37:51 +00002088 VNC_DEBUG("Handshake done, switching to TLS data mode\n");
2089 vs->wiremode = VNC_WIREMODE_TLS;
2090 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
2091
2092 return start_auth_vencrypt_subauth(vs);
2093}
2094
2095static void vnc_handshake_io(void *opaque) {
2096 struct VncState *vs = (struct VncState *)opaque;
2097
2098 VNC_DEBUG("Handshake IO continue\n");
2099 vnc_continue_handshake(vs);
2100}
2101
ths3a702692007-08-25 01:38:36 +00002102#define NEED_X509_AUTH(vs) \
aliguori753b4052009-02-16 14:59:30 +00002103 ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE || \
2104 (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC || \
2105 (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
ths3a702692007-08-25 01:38:36 +00002106
2107
ths8d5d2d42007-08-25 01:37:51 +00002108static int vnc_start_tls(struct VncState *vs) {
2109 static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
2110 static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
2111 static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
ths3a702692007-08-25 01:38:36 +00002112 static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
ths8d5d2d42007-08-25 01:37:51 +00002113
2114 VNC_DEBUG("Do TLS setup\n");
2115 if (vnc_tls_initialize() < 0) {
2116 VNC_DEBUG("Failed to init TLS\n");
2117 vnc_client_error(vs);
2118 return -1;
2119 }
2120 if (vs->tls_session == NULL) {
2121 if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) {
2122 vnc_client_error(vs);
2123 return -1;
2124 }
2125
2126 if (gnutls_set_default_priority(vs->tls_session) < 0) {
2127 gnutls_deinit(vs->tls_session);
2128 vs->tls_session = NULL;
2129 vnc_client_error(vs);
2130 return -1;
2131 }
2132
ths3a702692007-08-25 01:38:36 +00002133 if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) {
ths8d5d2d42007-08-25 01:37:51 +00002134 gnutls_deinit(vs->tls_session);
2135 vs->tls_session = NULL;
2136 vnc_client_error(vs);
2137 return -1;
2138 }
2139
2140 if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) {
2141 gnutls_deinit(vs->tls_session);
2142 vs->tls_session = NULL;
2143 vnc_client_error(vs);
2144 return -1;
2145 }
2146
2147 if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) {
2148 gnutls_deinit(vs->tls_session);
2149 vs->tls_session = NULL;
2150 vnc_client_error(vs);
2151 return -1;
2152 }
2153
ths3a702692007-08-25 01:38:36 +00002154 if (NEED_X509_AUTH(vs)) {
ths6f430242007-08-25 01:39:57 +00002155 gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs);
ths3a702692007-08-25 01:38:36 +00002156 if (!x509_cred) {
2157 gnutls_deinit(vs->tls_session);
2158 vs->tls_session = NULL;
2159 vnc_client_error(vs);
2160 return -1;
2161 }
2162 if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
2163 gnutls_deinit(vs->tls_session);
2164 vs->tls_session = NULL;
2165 gnutls_certificate_free_credentials(x509_cred);
2166 vnc_client_error(vs);
2167 return -1;
2168 }
aliguori753b4052009-02-16 14:59:30 +00002169 if (vs->vd->x509verify) {
ths469b15c2007-08-25 01:39:10 +00002170 VNC_DEBUG("Requesting a client certificate\n");
2171 gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
2172 }
2173
ths3a702692007-08-25 01:38:36 +00002174 } else {
2175 gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
2176 if (!anon_cred) {
2177 gnutls_deinit(vs->tls_session);
2178 vs->tls_session = NULL;
2179 vnc_client_error(vs);
2180 return -1;
2181 }
2182 if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
2183 gnutls_deinit(vs->tls_session);
2184 vs->tls_session = NULL;
2185 gnutls_anon_free_server_credentials(anon_cred);
2186 vnc_client_error(vs);
2187 return -1;
2188 }
ths8d5d2d42007-08-25 01:37:51 +00002189 }
2190
2191 gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs);
2192 gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push);
2193 gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull);
2194 }
2195
2196 VNC_DEBUG("Start TLS handshake process\n");
2197 return vnc_continue_handshake(vs);
2198}
2199
ths60fe76f2007-12-16 03:02:09 +00002200static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
ths8d5d2d42007-08-25 01:37:51 +00002201{
2202 int auth = read_u32(data, 0);
2203
aliguori753b4052009-02-16 14:59:30 +00002204 if (auth != vs->vd->subauth) {
ths8d5d2d42007-08-25 01:37:51 +00002205 VNC_DEBUG("Rejecting auth %d\n", auth);
2206 vnc_write_u8(vs, 0); /* Reject auth */
2207 vnc_flush(vs);
2208 vnc_client_error(vs);
2209 } else {
2210 VNC_DEBUG("Accepting auth %d, starting handshake\n", auth);
2211 vnc_write_u8(vs, 1); /* Accept auth */
2212 vnc_flush(vs);
2213
2214 if (vnc_start_tls(vs) < 0) {
2215 VNC_DEBUG("Failed to complete TLS\n");
2216 return 0;
2217 }
ths8d5d2d42007-08-25 01:37:51 +00002218 }
2219 return 0;
2220}
2221
ths60fe76f2007-12-16 03:02:09 +00002222static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
ths8d5d2d42007-08-25 01:37:51 +00002223{
2224 if (data[0] != 0 ||
2225 data[1] != 2) {
2226 VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
2227 vnc_write_u8(vs, 1); /* Reject version */
2228 vnc_flush(vs);
2229 vnc_client_error(vs);
2230 } else {
aliguori753b4052009-02-16 14:59:30 +00002231 VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
ths8d5d2d42007-08-25 01:37:51 +00002232 vnc_write_u8(vs, 0); /* Accept version */
2233 vnc_write_u8(vs, 1); /* Number of sub-auths */
aliguori753b4052009-02-16 14:59:30 +00002234 vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
ths8d5d2d42007-08-25 01:37:51 +00002235 vnc_flush(vs);
2236 vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
2237 }
2238 return 0;
2239}
2240
2241static int start_auth_vencrypt(VncState *vs)
2242{
2243 /* Send VeNCrypt version 0.2 */
2244 vnc_write_u8(vs, 0);
2245 vnc_write_u8(vs, 2);
2246
2247 vnc_read_when(vs, protocol_client_vencrypt_init, 2);
2248 return 0;
2249}
2250#endif /* CONFIG_VNC_TLS */
2251
ths60fe76f2007-12-16 03:02:09 +00002252static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002253{
2254 /* We only advertise 1 auth scheme at a time, so client
2255 * must pick the one we sent. Verify this */
aliguori753b4052009-02-16 14:59:30 +00002256 if (data[0] != vs->vd->auth) { /* Reject auth */
ths70848512007-08-25 01:37:05 +00002257 VNC_DEBUG("Reject auth %d\n", (int)data[0]);
2258 vnc_write_u32(vs, 1);
2259 if (vs->minor >= 8) {
2260 static const char err[] = "Authentication failed";
2261 vnc_write_u32(vs, sizeof(err));
2262 vnc_write(vs, err, sizeof(err));
2263 }
2264 vnc_client_error(vs);
2265 } else { /* Accept requested auth */
2266 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
aliguori753b4052009-02-16 14:59:30 +00002267 switch (vs->vd->auth) {
ths70848512007-08-25 01:37:05 +00002268 case VNC_AUTH_NONE:
2269 VNC_DEBUG("Accept auth none\n");
balroga26c97a2007-10-31 01:58:56 +00002270 if (vs->minor >= 8) {
2271 vnc_write_u32(vs, 0); /* Accept auth completion */
2272 vnc_flush(vs);
2273 }
ths70848512007-08-25 01:37:05 +00002274 vnc_read_when(vs, protocol_client_init, 1);
2275 break;
2276
2277 case VNC_AUTH_VNC:
2278 VNC_DEBUG("Start VNC auth\n");
2279 return start_auth_vnc(vs);
2280
blueswir1eb38c522008-09-06 17:47:39 +00002281#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002282 case VNC_AUTH_VENCRYPT:
2283 VNC_DEBUG("Accept VeNCrypt auth\n");;
2284 return start_auth_vencrypt(vs);
2285#endif /* CONFIG_VNC_TLS */
2286
ths70848512007-08-25 01:37:05 +00002287 default: /* Should not be possible, but just in case */
aliguori753b4052009-02-16 14:59:30 +00002288 VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002289 vnc_write_u8(vs, 1);
2290 if (vs->minor >= 8) {
2291 static const char err[] = "Authentication failed";
2292 vnc_write_u32(vs, sizeof(err));
2293 vnc_write(vs, err, sizeof(err));
2294 }
2295 vnc_client_error(vs);
2296 }
2297 }
2298 return 0;
2299}
2300
ths60fe76f2007-12-16 03:02:09 +00002301static int protocol_version(VncState *vs, uint8_t *version, size_t len)
ths70848512007-08-25 01:37:05 +00002302{
2303 char local[13];
2304
2305 memcpy(local, version, 12);
2306 local[12] = 0;
2307
2308 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
2309 VNC_DEBUG("Malformed protocol version %s\n", local);
2310 vnc_client_error(vs);
2311 return 0;
2312 }
2313 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2314 if (vs->major != 3 ||
2315 (vs->minor != 3 &&
thsb0566f42007-09-30 13:01:15 +00002316 vs->minor != 4 &&
ths70848512007-08-25 01:37:05 +00002317 vs->minor != 5 &&
2318 vs->minor != 7 &&
2319 vs->minor != 8)) {
2320 VNC_DEBUG("Unsupported client version\n");
2321 vnc_write_u32(vs, VNC_AUTH_INVALID);
2322 vnc_flush(vs);
2323 vnc_client_error(vs);
2324 return 0;
2325 }
thsb0566f42007-09-30 13:01:15 +00002326 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
ths70848512007-08-25 01:37:05 +00002327 * as equivalent to v3.3 by servers
2328 */
thsb0566f42007-09-30 13:01:15 +00002329 if (vs->minor == 4 || vs->minor == 5)
ths70848512007-08-25 01:37:05 +00002330 vs->minor = 3;
2331
2332 if (vs->minor == 3) {
aliguori753b4052009-02-16 14:59:30 +00002333 if (vs->vd->auth == VNC_AUTH_NONE) {
ths70848512007-08-25 01:37:05 +00002334 VNC_DEBUG("Tell client auth none\n");
aliguori753b4052009-02-16 14:59:30 +00002335 vnc_write_u32(vs, vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002336 vnc_flush(vs);
2337 vnc_read_when(vs, protocol_client_init, 1);
aliguori753b4052009-02-16 14:59:30 +00002338 } else if (vs->vd->auth == VNC_AUTH_VNC) {
ths70848512007-08-25 01:37:05 +00002339 VNC_DEBUG("Tell client VNC auth\n");
aliguori753b4052009-02-16 14:59:30 +00002340 vnc_write_u32(vs, vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002341 vnc_flush(vs);
2342 start_auth_vnc(vs);
2343 } else {
aliguori753b4052009-02-16 14:59:30 +00002344 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002345 vnc_write_u32(vs, VNC_AUTH_INVALID);
2346 vnc_flush(vs);
2347 vnc_client_error(vs);
2348 }
2349 } else {
aliguori753b4052009-02-16 14:59:30 +00002350 VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002351 vnc_write_u8(vs, 1); /* num auth */
aliguori753b4052009-02-16 14:59:30 +00002352 vnc_write_u8(vs, vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002353 vnc_read_when(vs, protocol_client_auth, 1);
2354 vnc_flush(vs);
2355 }
bellard24236862006-04-30 21:28:36 +00002356
2357 return 0;
2358}
2359
aliguori753b4052009-02-16 14:59:30 +00002360static void vnc_connect(VncDisplay *vd, int csock)
balrog3aa3eea2008-02-03 02:54:04 +00002361{
aliguori753b4052009-02-16 14:59:30 +00002362 VncState *vs = qemu_mallocz(sizeof(VncState));
2363 vs->csock = csock;
2364
2365 VNC_DEBUG("New client on socket %d\n", csock);
aliguori7d957bd2009-01-15 22:14:11 +00002366 dcl->idle = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002367 socket_set_nonblock(vs->csock);
2368 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
aliguori753b4052009-02-16 14:59:30 +00002369
2370 vs->vd = vd;
2371 vs->ds = vd->ds;
2372 vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
2373 vs->last_x = -1;
2374 vs->last_y = -1;
2375
2376 vs->as.freq = 44100;
2377 vs->as.nchannels = 2;
2378 vs->as.fmt = AUD_FMT_S16;
2379 vs->as.endianness = 0;
2380
2381 vnc_resize(vs);
balrog3aa3eea2008-02-03 02:54:04 +00002382 vnc_write(vs, "RFB 003.008\n", 12);
2383 vnc_flush(vs);
2384 vnc_read_when(vs, protocol_version, 12);
aliguori0e1f5a02008-11-24 19:29:13 +00002385 memset(vs->old_data, 0, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
balrog3aa3eea2008-02-03 02:54:04 +00002386 memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
balrog3aa3eea2008-02-03 02:54:04 +00002387 vnc_update_client(vs);
malc53762dd2008-12-01 20:57:52 +00002388 reset_keys(vs);
aliguori753b4052009-02-16 14:59:30 +00002389
2390 vs->next = vd->clients;
2391 vd->clients = vs;
balrog3aa3eea2008-02-03 02:54:04 +00002392}
2393
bellard24236862006-04-30 21:28:36 +00002394static void vnc_listen_read(void *opaque)
2395{
aliguori753b4052009-02-16 14:59:30 +00002396 VncDisplay *vs = opaque;
bellard24236862006-04-30 21:28:36 +00002397 struct sockaddr_in addr;
2398 socklen_t addrlen = sizeof(addr);
2399
balrog9f60ad52008-01-14 21:45:55 +00002400 /* Catch-up */
2401 vga_hw_update();
2402
aliguori753b4052009-02-16 14:59:30 +00002403 int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
2404 if (csock != -1) {
2405 vnc_connect(vs, csock);
bellard24236862006-04-30 21:28:36 +00002406 }
2407}
2408
ths71cab5c2007-08-25 01:35:38 +00002409void vnc_display_init(DisplayState *ds)
bellard24236862006-04-30 21:28:36 +00002410{
aliguori753b4052009-02-16 14:59:30 +00002411 VncDisplay *vs;
bellard24236862006-04-30 21:28:36 +00002412
2413 vs = qemu_mallocz(sizeof(VncState));
aliguori7d957bd2009-01-15 22:14:11 +00002414 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
bellard24236862006-04-30 21:28:36 +00002415
2416 ds->opaque = vs;
aliguori7d957bd2009-01-15 22:14:11 +00002417 dcl->idle = 1;
aliguori753b4052009-02-16 14:59:30 +00002418 vnc_display = vs;
bellard24236862006-04-30 21:28:36 +00002419
2420 vs->lsock = -1;
bellard24236862006-04-30 21:28:36 +00002421
2422 vs->ds = ds;
2423
aliguori9ca313a2008-08-23 23:27:37 +00002424 if (keyboard_layout)
2425 vs->kbd_layout = init_keyboard_layout(keyboard_layout);
2426 else
2427 vs->kbd_layout = init_keyboard_layout("en-us");
bellard24236862006-04-30 21:28:36 +00002428
bellard24236862006-04-30 21:28:36 +00002429 if (!vs->kbd_layout)
2430 exit(1);
2431
aliguori753b4052009-02-16 14:59:30 +00002432 dcl->dpy_copy = vnc_dpy_copy;
aliguori7d957bd2009-01-15 22:14:11 +00002433 dcl->dpy_update = vnc_dpy_update;
2434 dcl->dpy_resize = vnc_dpy_resize;
2435 dcl->dpy_setdata = vnc_dpy_setdata;
aliguori7d957bd2009-01-15 22:14:11 +00002436 register_displaychangelistener(ds, dcl);
ths71cab5c2007-08-25 01:35:38 +00002437}
ths73fc9742006-12-22 02:09:07 +00002438
blueswir1eb38c522008-09-06 17:47:39 +00002439#ifdef CONFIG_VNC_TLS
aliguori753b4052009-02-16 14:59:30 +00002440static int vnc_set_x509_credential(VncDisplay *vs,
ths6f430242007-08-25 01:39:57 +00002441 const char *certdir,
2442 const char *filename,
2443 char **cred,
2444 int ignoreMissing)
2445{
2446 struct stat sb;
2447
2448 if (*cred) {
2449 qemu_free(*cred);
2450 *cred = NULL;
2451 }
2452
aliguori1eec6142009-02-05 22:06:18 +00002453 *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
ths6f430242007-08-25 01:39:57 +00002454
2455 strcpy(*cred, certdir);
2456 strcat(*cred, "/");
2457 strcat(*cred, filename);
2458
2459 VNC_DEBUG("Check %s\n", *cred);
2460 if (stat(*cred, &sb) < 0) {
2461 qemu_free(*cred);
2462 *cred = NULL;
2463 if (ignoreMissing && errno == ENOENT)
2464 return 0;
2465 return -1;
2466 }
2467
2468 return 0;
2469}
2470
aliguori753b4052009-02-16 14:59:30 +00002471static int vnc_set_x509_credential_dir(VncDisplay *vs,
ths6f430242007-08-25 01:39:57 +00002472 const char *certdir)
2473{
2474 if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
2475 goto cleanup;
2476 if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0)
2477 goto cleanup;
2478 if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0)
2479 goto cleanup;
2480 if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0)
2481 goto cleanup;
2482
2483 return 0;
2484
2485 cleanup:
2486 qemu_free(vs->x509cacert);
2487 qemu_free(vs->x509cacrl);
2488 qemu_free(vs->x509cert);
2489 qemu_free(vs->x509key);
2490 vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL;
2491 return -1;
2492}
2493#endif /* CONFIG_VNC_TLS */
2494
ths71cab5c2007-08-25 01:35:38 +00002495void vnc_display_close(DisplayState *ds)
2496{
aliguori753b4052009-02-16 14:59:30 +00002497 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths71cab5c2007-08-25 01:35:38 +00002498
aliguori452b4d82009-02-11 21:00:38 +00002499 if (!vs)
2500 return;
ths71cab5c2007-08-25 01:35:38 +00002501 if (vs->display) {
2502 qemu_free(vs->display);
2503 vs->display = NULL;
2504 }
2505 if (vs->lsock != -1) {
2506 qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
2507 close(vs->lsock);
2508 vs->lsock = -1;
2509 }
ths70848512007-08-25 01:37:05 +00002510 vs->auth = VNC_AUTH_INVALID;
blueswir1eb38c522008-09-06 17:47:39 +00002511#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002512 vs->subauth = VNC_AUTH_INVALID;
ths469b15c2007-08-25 01:39:10 +00002513 vs->x509verify = 0;
ths8d5d2d42007-08-25 01:37:51 +00002514#endif
ths71cab5c2007-08-25 01:35:38 +00002515}
2516
ths70848512007-08-25 01:37:05 +00002517int vnc_display_password(DisplayState *ds, const char *password)
2518{
aliguori753b4052009-02-16 14:59:30 +00002519 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths70848512007-08-25 01:37:05 +00002520
2521 if (vs->password) {
2522 qemu_free(vs->password);
2523 vs->password = NULL;
2524 }
2525 if (password && password[0]) {
2526 if (!(vs->password = qemu_strdup(password)))
2527 return -1;
2528 }
2529
2530 return 0;
2531}
2532
2533int vnc_display_open(DisplayState *ds, const char *display)
ths71cab5c2007-08-25 01:35:38 +00002534{
aliguori753b4052009-02-16 14:59:30 +00002535 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths70848512007-08-25 01:37:05 +00002536 const char *options;
2537 int password = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002538 int reverse = 0;
aliguori9712eca2008-11-11 20:51:59 +00002539 int to_port = 0;
blueswir1eb38c522008-09-06 17:47:39 +00002540#ifdef CONFIG_VNC_TLS
ths3a702692007-08-25 01:38:36 +00002541 int tls = 0, x509 = 0;
ths8d5d2d42007-08-25 01:37:51 +00002542#endif
ths71cab5c2007-08-25 01:35:38 +00002543
aliguori753b4052009-02-16 14:59:30 +00002544 if (!vnc_display)
aliguori452b4d82009-02-11 21:00:38 +00002545 return -1;
ths71cab5c2007-08-25 01:35:38 +00002546 vnc_display_close(ds);
ths70848512007-08-25 01:37:05 +00002547 if (strcmp(display, "none") == 0)
ths71cab5c2007-08-25 01:35:38 +00002548 return 0;
2549
ths70848512007-08-25 01:37:05 +00002550 if (!(vs->display = strdup(display)))
ths71cab5c2007-08-25 01:35:38 +00002551 return -1;
ths70848512007-08-25 01:37:05 +00002552
2553 options = display;
2554 while ((options = strchr(options, ','))) {
2555 options++;
ths469b15c2007-08-25 01:39:10 +00002556 if (strncmp(options, "password", 8) == 0) {
ths70848512007-08-25 01:37:05 +00002557 password = 1; /* Require password auth */
balrog3aa3eea2008-02-03 02:54:04 +00002558 } else if (strncmp(options, "reverse", 7) == 0) {
2559 reverse = 1;
aliguori9712eca2008-11-11 20:51:59 +00002560 } else if (strncmp(options, "to=", 3) == 0) {
2561 to_port = atoi(options+3) + 5900;
blueswir1eb38c522008-09-06 17:47:39 +00002562#ifdef CONFIG_VNC_TLS
ths469b15c2007-08-25 01:39:10 +00002563 } else if (strncmp(options, "tls", 3) == 0) {
ths8d5d2d42007-08-25 01:37:51 +00002564 tls = 1; /* Require TLS */
ths469b15c2007-08-25 01:39:10 +00002565 } else if (strncmp(options, "x509", 4) == 0) {
ths6f430242007-08-25 01:39:57 +00002566 char *start, *end;
ths3a702692007-08-25 01:38:36 +00002567 x509 = 1; /* Require x509 certificates */
ths6f430242007-08-25 01:39:57 +00002568 if (strncmp(options, "x509verify", 10) == 0)
2569 vs->x509verify = 1; /* ...and verify client certs */
2570
2571 /* Now check for 'x509=/some/path' postfix
2572 * and use that to setup x509 certificate/key paths */
2573 start = strchr(options, '=');
2574 end = strchr(options, ',');
2575 if (start && (!end || (start < end))) {
2576 int len = end ? end-(start+1) : strlen(start+1);
balrogbe351262008-11-12 16:50:36 +00002577 char *path = qemu_strndup(start + 1, len);
blueswir1be15b142008-10-25 11:21:28 +00002578
ths6f430242007-08-25 01:39:57 +00002579 VNC_DEBUG("Trying certificate path '%s'\n", path);
2580 if (vnc_set_x509_credential_dir(vs, path) < 0) {
2581 fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
2582 qemu_free(path);
2583 qemu_free(vs->display);
2584 vs->display = NULL;
2585 return -1;
2586 }
2587 qemu_free(path);
2588 } else {
2589 fprintf(stderr, "No certificate path provided\n");
2590 qemu_free(vs->display);
2591 vs->display = NULL;
2592 return -1;
2593 }
ths8d5d2d42007-08-25 01:37:51 +00002594#endif
ths469b15c2007-08-25 01:39:10 +00002595 }
ths70848512007-08-25 01:37:05 +00002596 }
2597
2598 if (password) {
blueswir1eb38c522008-09-06 17:47:39 +00002599#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002600 if (tls) {
ths8d5d2d42007-08-25 01:37:51 +00002601 vs->auth = VNC_AUTH_VENCRYPT;
ths3a702692007-08-25 01:38:36 +00002602 if (x509) {
2603 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
2604 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
2605 } else {
2606 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
2607 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
2608 }
ths8d5d2d42007-08-25 01:37:51 +00002609 } else {
2610#endif
2611 VNC_DEBUG("Initializing VNC server with password auth\n");
2612 vs->auth = VNC_AUTH_VNC;
blueswir1eb38c522008-09-06 17:47:39 +00002613#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002614 vs->subauth = VNC_AUTH_INVALID;
2615 }
2616#endif
ths70848512007-08-25 01:37:05 +00002617 } else {
blueswir1eb38c522008-09-06 17:47:39 +00002618#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002619 if (tls) {
ths8d5d2d42007-08-25 01:37:51 +00002620 vs->auth = VNC_AUTH_VENCRYPT;
ths3a702692007-08-25 01:38:36 +00002621 if (x509) {
2622 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
2623 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
2624 } else {
2625 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
2626 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
2627 }
ths8d5d2d42007-08-25 01:37:51 +00002628 } else {
2629#endif
2630 VNC_DEBUG("Initializing VNC server with no auth\n");
2631 vs->auth = VNC_AUTH_NONE;
blueswir1eb38c522008-09-06 17:47:39 +00002632#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002633 vs->subauth = VNC_AUTH_INVALID;
2634 }
2635#endif
ths70848512007-08-25 01:37:05 +00002636 }
bellard24236862006-04-30 21:28:36 +00002637
balrog3aa3eea2008-02-03 02:54:04 +00002638 if (reverse) {
aliguori9712eca2008-11-11 20:51:59 +00002639 /* connect to viewer */
2640 if (strncmp(display, "unix:", 5) == 0)
2641 vs->lsock = unix_connect(display+5);
2642 else
2643 vs->lsock = inet_connect(display, SOCK_STREAM);
2644 if (-1 == vs->lsock) {
balrog3aa3eea2008-02-03 02:54:04 +00002645 free(vs->display);
2646 vs->display = NULL;
2647 return -1;
2648 } else {
aliguori753b4052009-02-16 14:59:30 +00002649 int csock = vs->lsock;
balrog3aa3eea2008-02-03 02:54:04 +00002650 vs->lsock = -1;
aliguori753b4052009-02-16 14:59:30 +00002651 vnc_connect(vs, csock);
balrog3aa3eea2008-02-03 02:54:04 +00002652 }
aliguori9712eca2008-11-11 20:51:59 +00002653 return 0;
balrog3aa3eea2008-02-03 02:54:04 +00002654
aliguori9712eca2008-11-11 20:51:59 +00002655 } else {
2656 /* listen for connects */
2657 char *dpy;
2658 dpy = qemu_malloc(256);
2659 if (strncmp(display, "unix:", 5) == 0) {
blueswir1bc575e92009-01-14 18:34:22 +00002660 pstrcpy(dpy, 256, "unix:");
aliguori4a55bfd2008-12-02 20:02:14 +00002661 vs->lsock = unix_listen(display+5, dpy+5, 256-5);
aliguori9712eca2008-11-11 20:51:59 +00002662 } else {
2663 vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
2664 }
2665 if (-1 == vs->lsock) {
2666 free(dpy);
balrogd0513622008-12-01 01:48:36 +00002667 return -1;
aliguori9712eca2008-11-11 20:51:59 +00002668 } else {
2669 free(vs->display);
2670 vs->display = dpy;
2671 }
bellard24236862006-04-30 21:28:36 +00002672 }
aliguori753b4052009-02-16 14:59:30 +00002673 return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00002674}