blob: 575fd68983d21ba8c95c56ff2ca85526198d93b4 [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"
27#include "console.h"
28#include "sysemu.h"
bellard6ca957f2006-04-30 22:53:25 +000029#include "qemu_socket.h"
pbrook87ecb682007-11-17 17:14:51 +000030#include "qemu-timer.h"
malc429a8ed2008-12-01 20:57:48 +000031#include "audio/audio.h"
bellard24236862006-04-30 21:28:36 +000032
33#define VNC_REFRESH_INTERVAL (1000 / 30)
34
35#include "vnc_keysym.h"
36#include "keymaps.c"
ths70848512007-08-25 01:37:05 +000037#include "d3des.h"
38
blueswir1eb38c522008-09-06 17:47:39 +000039#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +000040#include <gnutls/gnutls.h>
41#include <gnutls/x509.h>
42#endif /* CONFIG_VNC_TLS */
ths70848512007-08-25 01:37:05 +000043
ths8d5d2d42007-08-25 01:37:51 +000044// #define _VNC_DEBUG 1
45
blueswir1eb38c522008-09-06 17:47:39 +000046#ifdef _VNC_DEBUG
ths70848512007-08-25 01:37:05 +000047#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
ths8d5d2d42007-08-25 01:37:51 +000048
49#if CONFIG_VNC_TLS && _VNC_DEBUG >= 2
50/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
51static void vnc_debug_gnutls_log(int level, const char* str) {
52 VNC_DEBUG("%d %s", level, str);
53}
54#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
ths70848512007-08-25 01:37:05 +000055#else
56#define VNC_DEBUG(fmt, ...) do { } while (0)
57#endif
bellard24236862006-04-30 21:28:36 +000058
ths8d5d2d42007-08-25 01:37:51 +000059
bellard24236862006-04-30 21:28:36 +000060typedef struct Buffer
61{
62 size_t capacity;
63 size_t offset;
ths60fe76f2007-12-16 03:02:09 +000064 uint8_t *buffer;
bellard24236862006-04-30 21:28:36 +000065} Buffer;
66
67typedef struct VncState VncState;
68
ths60fe76f2007-12-16 03:02:09 +000069typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
bellard24236862006-04-30 21:28:36 +000070
bellard35127792006-05-14 18:11:49 +000071typedef void VncWritePixels(VncState *vs, void *data, int size);
72
73typedef void VncSendHextileTile(VncState *vs,
74 int x, int y, int w, int h,
aliguori7eac3a82008-09-15 16:03:41 +000075 void *last_bg,
76 void *last_fg,
bellard35127792006-05-14 18:11:49 +000077 int *has_bg, int *has_fg);
78
bellard99589bd2006-06-13 16:35:24 +000079#define VNC_MAX_WIDTH 2048
80#define VNC_MAX_HEIGHT 2048
81#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
82
ths70848512007-08-25 01:37:05 +000083#define VNC_AUTH_CHALLENGE_SIZE 16
84
85enum {
86 VNC_AUTH_INVALID = 0,
87 VNC_AUTH_NONE = 1,
88 VNC_AUTH_VNC = 2,
89 VNC_AUTH_RA2 = 5,
90 VNC_AUTH_RA2NE = 6,
91 VNC_AUTH_TIGHT = 16,
92 VNC_AUTH_ULTRA = 17,
93 VNC_AUTH_TLS = 18,
94 VNC_AUTH_VENCRYPT = 19
95};
96
blueswir1eb38c522008-09-06 17:47:39 +000097#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +000098enum {
99 VNC_WIREMODE_CLEAR,
100 VNC_WIREMODE_TLS,
101};
102
103enum {
104 VNC_AUTH_VENCRYPT_PLAIN = 256,
105 VNC_AUTH_VENCRYPT_TLSNONE = 257,
106 VNC_AUTH_VENCRYPT_TLSVNC = 258,
107 VNC_AUTH_VENCRYPT_TLSPLAIN = 259,
108 VNC_AUTH_VENCRYPT_X509NONE = 260,
109 VNC_AUTH_VENCRYPT_X509VNC = 261,
110 VNC_AUTH_VENCRYPT_X509PLAIN = 262,
111};
ths3a702692007-08-25 01:38:36 +0000112
ths3a702692007-08-25 01:38:36 +0000113#define X509_CA_CERT_FILE "ca-cert.pem"
114#define X509_CA_CRL_FILE "ca-crl.pem"
115#define X509_SERVER_KEY_FILE "server-key.pem"
116#define X509_SERVER_CERT_FILE "server-cert.pem"
ths3a702692007-08-25 01:38:36 +0000117
ths8d5d2d42007-08-25 01:37:51 +0000118#endif /* CONFIG_VNC_TLS */
119
bellard24236862006-04-30 21:28:36 +0000120struct VncState
121{
122 QEMUTimer *timer;
123 int lsock;
124 int csock;
125 DisplayState *ds;
126 int need_update;
127 int width;
128 int height;
bellard99589bd2006-06-13 16:35:24 +0000129 uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
bellard24236862006-04-30 21:28:36 +0000130 char *old_data;
bellard35127792006-05-14 18:11:49 +0000131 int depth; /* internal VNC frame buffer byte per pixel */
bellard24236862006-04-30 21:28:36 +0000132 int has_resize;
133 int has_hextile;
bellard564c3372007-02-05 20:14:10 +0000134 int has_pointer_type_change;
aliguorica4cca42008-09-15 16:05:16 +0000135 int has_WMVi;
bellard564c3372007-02-05 20:14:10 +0000136 int absolute;
137 int last_x;
138 int last_y;
139
ths70848512007-08-25 01:37:05 +0000140 int major;
141 int minor;
142
ths71cab5c2007-08-25 01:35:38 +0000143 char *display;
ths70848512007-08-25 01:37:05 +0000144 char *password;
145 int auth;
blueswir1eb38c522008-09-06 17:47:39 +0000146#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000147 int subauth;
ths469b15c2007-08-25 01:39:10 +0000148 int x509verify;
ths6f430242007-08-25 01:39:57 +0000149
150 char *x509cacert;
151 char *x509cacrl;
152 char *x509cert;
153 char *x509key;
ths8d5d2d42007-08-25 01:37:51 +0000154#endif
ths70848512007-08-25 01:37:05 +0000155 char challenge[VNC_AUTH_CHALLENGE_SIZE];
bellarda9ce8592007-02-05 20:20:30 +0000156
blueswir1eb38c522008-09-06 17:47:39 +0000157#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000158 int wiremode;
159 gnutls_session_t tls_session;
160#endif
161
bellard24236862006-04-30 21:28:36 +0000162 Buffer output;
163 Buffer input;
164 kbd_layout_t *kbd_layout;
bellard35127792006-05-14 18:11:49 +0000165 /* current output mode information */
166 VncWritePixels *write_pixels;
167 VncSendHextileTile *send_hextile_tile;
168 int pix_bpp, pix_big_endian;
aliguori7eac3a82008-09-15 16:03:41 +0000169 int client_red_shift, client_red_max, server_red_shift, server_red_max;
170 int client_green_shift, client_green_max, server_green_shift, server_green_max;
171 int client_blue_shift, client_blue_max, server_blue_shift, server_blue_max;
bellard24236862006-04-30 21:28:36 +0000172
malc429a8ed2008-12-01 20:57:48 +0000173 CaptureVoiceOut *audio_cap;
malc1ea879e2008-12-03 22:48:44 +0000174 struct audsettings as;
malc429a8ed2008-12-01 20:57:48 +0000175
bellard24236862006-04-30 21:28:36 +0000176 VncReadEvent *read_handler;
177 size_t read_handler_expect;
bellard64f5a132006-08-24 20:36:44 +0000178 /* input */
179 uint8_t modifiers_state[256];
bellard24236862006-04-30 21:28:36 +0000180};
181
bellarda9ce8592007-02-05 20:20:30 +0000182static VncState *vnc_state; /* needed for info vnc */
183
184void do_info_vnc(void)
185{
aurel3213412c92008-12-13 18:57:12 +0000186 if (vnc_state == NULL || vnc_state->display == NULL)
bellarda9ce8592007-02-05 20:20:30 +0000187 term_printf("VNC server disabled\n");
188 else {
189 term_printf("VNC server active on: ");
190 term_print_filename(vnc_state->display);
191 term_printf("\n");
192
193 if (vnc_state->csock == -1)
194 term_printf("No client connected\n");
195 else
196 term_printf("Client connected\n");
197 }
198}
199
bellard24236862006-04-30 21:28:36 +0000200/* TODO
201 1) Get the queue working for IO.
202 2) there is some weirdness when using the -S option (the screen is grey
203 and not totally invalidated
204 3) resolutions > 1024
205*/
206
207static void vnc_write(VncState *vs, const void *data, size_t len);
208static void vnc_write_u32(VncState *vs, uint32_t value);
209static void vnc_write_s32(VncState *vs, int32_t value);
210static void vnc_write_u16(VncState *vs, uint16_t value);
211static void vnc_write_u8(VncState *vs, uint8_t value);
212static void vnc_flush(VncState *vs);
213static void vnc_update_client(void *opaque);
214static void vnc_client_read(void *opaque);
215
aliguori7eac3a82008-09-15 16:03:41 +0000216static void vnc_colordepth(DisplayState *ds, int depth);
217
bellard99589bd2006-06-13 16:35:24 +0000218static inline void vnc_set_bit(uint32_t *d, int k)
219{
220 d[k >> 5] |= 1 << (k & 0x1f);
221}
222
223static inline void vnc_clear_bit(uint32_t *d, int k)
224{
225 d[k >> 5] &= ~(1 << (k & 0x1f));
226}
227
228static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
229{
230 int j;
231
232 j = 0;
233 while (n >= 32) {
234 d[j++] = -1;
235 n -= 32;
236 }
ths5fafdf22007-09-16 21:08:06 +0000237 if (n > 0)
bellard99589bd2006-06-13 16:35:24 +0000238 d[j++] = (1 << n) - 1;
239 while (j < nb_words)
240 d[j++] = 0;
241}
242
243static inline int vnc_get_bit(const uint32_t *d, int k)
244{
245 return (d[k >> 5] >> (k & 0x1f)) & 1;
246}
247
ths5fafdf22007-09-16 21:08:06 +0000248static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
bellard99589bd2006-06-13 16:35:24 +0000249 int nb_words)
250{
251 int i;
252 for(i = 0; i < nb_words; i++) {
253 if ((d1[i] & d2[i]) != 0)
254 return 1;
255 }
256 return 0;
257}
258
bellard24236862006-04-30 21:28:36 +0000259static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
260{
261 VncState *vs = ds->opaque;
262 int i;
263
264 h += y;
265
balrog0486e8a2007-12-11 22:31:32 +0000266 /* round x down to ensure the loop only spans one 16-pixel block per,
267 iteration. otherwise, if (x % 16) != 0, the last iteration may span
268 two 16-pixel blocks but we only mark the first as dirty
269 */
270 w += (x % 16);
271 x -= (x % 16);
272
balrog788abf82008-05-20 00:07:58 +0000273 x = MIN(x, vs->width);
274 y = MIN(y, vs->height);
275 w = MIN(x + w, vs->width) - x;
balrog731dd632008-05-25 00:38:47 +0000276 h = MIN(h, vs->height);
balrog788abf82008-05-20 00:07:58 +0000277
bellard24236862006-04-30 21:28:36 +0000278 for (; y < h; y++)
279 for (i = 0; i < w; i += 16)
bellard99589bd2006-06-13 16:35:24 +0000280 vnc_set_bit(vs->dirty_row[y], (x + i) / 16);
bellard24236862006-04-30 21:28:36 +0000281}
282
283static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
284 int32_t encoding)
285{
286 vnc_write_u16(vs, x);
287 vnc_write_u16(vs, y);
288 vnc_write_u16(vs, w);
289 vnc_write_u16(vs, h);
290
291 vnc_write_s32(vs, encoding);
292}
293
294static void vnc_dpy_resize(DisplayState *ds, int w, int h)
295{
ths73e14b62006-12-14 13:36:01 +0000296 int size_changed;
bellard24236862006-04-30 21:28:36 +0000297 VncState *vs = ds->opaque;
298
ths2137b4c2008-08-06 08:37:17 +0000299 ds->data = qemu_realloc(ds->data, w * h * vs->depth);
300 vs->old_data = qemu_realloc(vs->old_data, w * h * vs->depth);
bellard24236862006-04-30 21:28:36 +0000301
302 if (ds->data == NULL || vs->old_data == NULL) {
303 fprintf(stderr, "vnc: memory allocation failed\n");
304 exit(1);
305 }
306
balroga528b802007-10-30 22:38:53 +0000307 if (ds->depth != vs->depth * 8) {
308 ds->depth = vs->depth * 8;
309 console_color_init(ds);
310 }
ths73e14b62006-12-14 13:36:01 +0000311 size_changed = ds->width != w || ds->height != h;
bellard24236862006-04-30 21:28:36 +0000312 ds->width = w;
313 ds->height = h;
314 ds->linesize = w * vs->depth;
balrogb94eb432008-06-02 01:40:29 +0000315 if (size_changed) {
316 vs->width = ds->width;
317 vs->height = ds->height;
318 if (vs->csock != -1 && vs->has_resize) {
319 vnc_write_u8(vs, 0); /* msg id */
320 vnc_write_u8(vs, 0);
321 vnc_write_u16(vs, 1); /* number of rects */
322 vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223);
323 vnc_flush(vs);
324 }
bellard24236862006-04-30 21:28:36 +0000325 }
balrog8bba5c82008-05-25 00:14:34 +0000326
327 memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
aliguori0e1f5a02008-11-24 19:29:13 +0000328 memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
bellard24236862006-04-30 21:28:36 +0000329}
330
bellard35127792006-05-14 18:11:49 +0000331/* fastest code */
332static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
333{
334 vnc_write(vs, pixels, size);
335}
336
337/* slowest but generic code. */
338static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
339{
aliguori7eac3a82008-09-15 16:03:41 +0000340 uint8_t r, g, b;
bellard35127792006-05-14 18:11:49 +0000341
aliguori7eac3a82008-09-15 16:03:41 +0000342 r = ((v >> vs->server_red_shift) & vs->server_red_max) * (vs->client_red_max + 1) /
343 (vs->server_red_max + 1);
344 g = ((v >> vs->server_green_shift) & vs->server_green_max) * (vs->client_green_max + 1) /
345 (vs->server_green_max + 1);
346 b = ((v >> vs->server_blue_shift) & vs->server_blue_max) * (vs->client_blue_max + 1) /
347 (vs->server_blue_max + 1);
348 v = (r << vs->client_red_shift) |
349 (g << vs->client_green_shift) |
350 (b << vs->client_blue_shift);
bellard35127792006-05-14 18:11:49 +0000351 switch(vs->pix_bpp) {
352 case 1:
353 buf[0] = v;
354 break;
355 case 2:
356 if (vs->pix_big_endian) {
357 buf[0] = v >> 8;
358 buf[1] = v;
359 } else {
360 buf[1] = v >> 8;
361 buf[0] = v;
362 }
363 break;
364 default:
365 case 4:
366 if (vs->pix_big_endian) {
367 buf[0] = v >> 24;
368 buf[1] = v >> 16;
369 buf[2] = v >> 8;
370 buf[3] = v;
371 } else {
372 buf[3] = v >> 24;
373 buf[2] = v >> 16;
374 buf[1] = v >> 8;
375 buf[0] = v;
376 }
377 break;
378 }
379}
380
381static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
382{
bellard35127792006-05-14 18:11:49 +0000383 uint8_t buf[4];
bellard35127792006-05-14 18:11:49 +0000384
aliguori7eac3a82008-09-15 16:03:41 +0000385 if (vs->depth == 4) {
386 uint32_t *pixels = pixels1;
387 int n, i;
388 n = size >> 2;
389 for(i = 0; i < n; i++) {
390 vnc_convert_pixel(vs, buf, pixels[i]);
391 vnc_write(vs, buf, vs->pix_bpp);
392 }
393 } else if (vs->depth == 2) {
394 uint16_t *pixels = pixels1;
395 int n, i;
396 n = size >> 1;
397 for(i = 0; i < n; i++) {
398 vnc_convert_pixel(vs, buf, pixels[i]);
399 vnc_write(vs, buf, vs->pix_bpp);
400 }
401 } else if (vs->depth == 1) {
402 uint8_t *pixels = pixels1;
403 int n, i;
404 n = size;
405 for(i = 0; i < n; i++) {
406 vnc_convert_pixel(vs, buf, pixels[i]);
407 vnc_write(vs, buf, vs->pix_bpp);
408 }
409 } else {
410 fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
bellard35127792006-05-14 18:11:49 +0000411 }
412}
413
bellard24236862006-04-30 21:28:36 +0000414static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
415{
416 int i;
ths60fe76f2007-12-16 03:02:09 +0000417 uint8_t *row;
bellard24236862006-04-30 21:28:36 +0000418
419 vnc_framebuffer_update(vs, x, y, w, h, 0);
420
aliguori0e1f5a02008-11-24 19:29:13 +0000421 row = ds_get_data(vs->ds) + y * ds_get_linesize(vs->ds) + x * vs->depth;
bellard24236862006-04-30 21:28:36 +0000422 for (i = 0; i < h; i++) {
bellard35127792006-05-14 18:11:49 +0000423 vs->write_pixels(vs, row, w * vs->depth);
aliguori0e1f5a02008-11-24 19:29:13 +0000424 row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +0000425 }
426}
427
428static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
429{
430 ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
431 ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
432}
433
434#define BPP 8
435#include "vnchextile.h"
436#undef BPP
437
438#define BPP 16
439#include "vnchextile.h"
440#undef BPP
441
442#define BPP 32
443#include "vnchextile.h"
444#undef BPP
445
bellard35127792006-05-14 18:11:49 +0000446#define GENERIC
aliguori7eac3a82008-09-15 16:03:41 +0000447#define BPP 8
448#include "vnchextile.h"
449#undef BPP
450#undef GENERIC
451
452#define GENERIC
453#define BPP 16
454#include "vnchextile.h"
455#undef BPP
456#undef GENERIC
457
458#define GENERIC
bellard35127792006-05-14 18:11:49 +0000459#define BPP 32
460#include "vnchextile.h"
461#undef BPP
462#undef GENERIC
463
bellard24236862006-04-30 21:28:36 +0000464static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
465{
466 int i, j;
467 int has_fg, has_bg;
aliguori7eac3a82008-09-15 16:03:41 +0000468 uint8_t *last_fg, *last_bg;
bellard24236862006-04-30 21:28:36 +0000469
470 vnc_framebuffer_update(vs, x, y, w, h, 5);
471
aliguori7eac3a82008-09-15 16:03:41 +0000472 last_fg = (uint8_t *) malloc(vs->depth);
473 last_bg = (uint8_t *) malloc(vs->depth);
bellard24236862006-04-30 21:28:36 +0000474 has_fg = has_bg = 0;
475 for (j = y; j < (y + h); j += 16) {
476 for (i = x; i < (x + w); i += 16) {
ths5fafdf22007-09-16 21:08:06 +0000477 vs->send_hextile_tile(vs, i, j,
bellard35127792006-05-14 18:11:49 +0000478 MIN(16, x + w - i), MIN(16, y + h - j),
aliguori7eac3a82008-09-15 16:03:41 +0000479 last_bg, last_fg, &has_bg, &has_fg);
bellard24236862006-04-30 21:28:36 +0000480 }
481 }
aliguori7eac3a82008-09-15 16:03:41 +0000482 free(last_fg);
483 free(last_bg);
484
bellard24236862006-04-30 21:28:36 +0000485}
486
487static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
488{
489 if (vs->has_hextile)
490 send_framebuffer_update_hextile(vs, x, y, w, h);
491 else
492 send_framebuffer_update_raw(vs, x, y, w, h);
493}
494
495static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
496{
497 int src, dst;
ths60fe76f2007-12-16 03:02:09 +0000498 uint8_t *src_row;
499 uint8_t *dst_row;
bellard24236862006-04-30 21:28:36 +0000500 char *old_row;
501 int y = 0;
aliguori0e1f5a02008-11-24 19:29:13 +0000502 int pitch = ds_get_linesize(ds);
bellard24236862006-04-30 21:28:36 +0000503 VncState *vs = ds->opaque;
504
505 vnc_update_client(vs);
506
507 if (dst_y > src_y) {
508 y = h - 1;
509 pitch = -pitch;
510 }
511
aliguori0e1f5a02008-11-24 19:29:13 +0000512 src = (ds_get_linesize(ds) * (src_y + y) + vs->depth * src_x);
513 dst = (ds_get_linesize(ds) * (dst_y + y) + vs->depth * dst_x);
bellard24236862006-04-30 21:28:36 +0000514
aliguori0e1f5a02008-11-24 19:29:13 +0000515 src_row = ds_get_data(ds) + src;
516 dst_row = ds_get_data(ds) + dst;
bellard24236862006-04-30 21:28:36 +0000517 old_row = vs->old_data + dst;
518
519 for (y = 0; y < h; y++) {
520 memmove(old_row, src_row, w * vs->depth);
521 memmove(dst_row, src_row, w * vs->depth);
522 src_row += pitch;
523 dst_row += pitch;
524 old_row += pitch;
525 }
526
527 vnc_write_u8(vs, 0); /* msg id */
528 vnc_write_u8(vs, 0);
529 vnc_write_u16(vs, 1); /* number of rects */
530 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, 1);
531 vnc_write_u16(vs, src_x);
532 vnc_write_u16(vs, src_y);
533 vnc_flush(vs);
534}
535
536static int find_dirty_height(VncState *vs, int y, int last_x, int x)
537{
538 int h;
539
540 for (h = 1; h < (vs->height - y); h++) {
541 int tmp_x;
bellard99589bd2006-06-13 16:35:24 +0000542 if (!vnc_get_bit(vs->dirty_row[y + h], last_x))
bellard24236862006-04-30 21:28:36 +0000543 break;
544 for (tmp_x = last_x; tmp_x < x; tmp_x++)
bellard99589bd2006-06-13 16:35:24 +0000545 vnc_clear_bit(vs->dirty_row[y + h], tmp_x);
bellard24236862006-04-30 21:28:36 +0000546 }
547
548 return h;
549}
550
551static void vnc_update_client(void *opaque)
552{
553 VncState *vs = opaque;
554
555 if (vs->need_update && vs->csock != -1) {
556 int y;
ths60fe76f2007-12-16 03:02:09 +0000557 uint8_t *row;
bellard24236862006-04-30 21:28:36 +0000558 char *old_row;
bellard99589bd2006-06-13 16:35:24 +0000559 uint32_t width_mask[VNC_DIRTY_WORDS];
bellard24236862006-04-30 21:28:36 +0000560 int n_rectangles;
561 int saved_offset;
562 int has_dirty = 0;
563
balroga0ecfb72008-01-13 23:51:53 +0000564 vga_hw_update();
565
bellard99589bd2006-06-13 16:35:24 +0000566 vnc_set_bits(width_mask, (vs->width / 16), VNC_DIRTY_WORDS);
bellard24236862006-04-30 21:28:36 +0000567
568 /* Walk through the dirty map and eliminate tiles that
569 really aren't dirty */
aliguori0e1f5a02008-11-24 19:29:13 +0000570 row = ds_get_data(vs->ds);
bellard24236862006-04-30 21:28:36 +0000571 old_row = vs->old_data;
572
573 for (y = 0; y < vs->height; y++) {
bellard99589bd2006-06-13 16:35:24 +0000574 if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) {
bellard24236862006-04-30 21:28:36 +0000575 int x;
ths60fe76f2007-12-16 03:02:09 +0000576 uint8_t *ptr;
577 char *old_ptr;
bellard24236862006-04-30 21:28:36 +0000578
579 ptr = row;
ths60fe76f2007-12-16 03:02:09 +0000580 old_ptr = (char*)old_row;
bellard24236862006-04-30 21:28:36 +0000581
aliguori0e1f5a02008-11-24 19:29:13 +0000582 for (x = 0; x < ds_get_width(vs->ds); x += 16) {
bellard24236862006-04-30 21:28:36 +0000583 if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) {
bellard99589bd2006-06-13 16:35:24 +0000584 vnc_clear_bit(vs->dirty_row[y], (x / 16));
bellard24236862006-04-30 21:28:36 +0000585 } else {
586 has_dirty = 1;
587 memcpy(old_ptr, ptr, 16 * vs->depth);
588 }
589
590 ptr += 16 * vs->depth;
591 old_ptr += 16 * vs->depth;
592 }
593 }
594
aliguori0e1f5a02008-11-24 19:29:13 +0000595 row += ds_get_linesize(vs->ds);
596 old_row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +0000597 }
598
malc429a8ed2008-12-01 20:57:48 +0000599 if (!has_dirty && !vs->audio_cap) {
bellard24236862006-04-30 21:28:36 +0000600 qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
601 return;
602 }
603
604 /* Count rectangles */
605 n_rectangles = 0;
606 vnc_write_u8(vs, 0); /* msg id */
607 vnc_write_u8(vs, 0);
608 saved_offset = vs->output.offset;
609 vnc_write_u16(vs, 0);
610
611 for (y = 0; y < vs->height; y++) {
612 int x;
613 int last_x = -1;
614 for (x = 0; x < vs->width / 16; x++) {
bellard99589bd2006-06-13 16:35:24 +0000615 if (vnc_get_bit(vs->dirty_row[y], x)) {
bellard24236862006-04-30 21:28:36 +0000616 if (last_x == -1) {
617 last_x = x;
618 }
bellard99589bd2006-06-13 16:35:24 +0000619 vnc_clear_bit(vs->dirty_row[y], x);
bellard24236862006-04-30 21:28:36 +0000620 } else {
621 if (last_x != -1) {
622 int h = find_dirty_height(vs, y, last_x, x);
623 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
624 n_rectangles++;
625 }
626 last_x = -1;
627 }
628 }
629 if (last_x != -1) {
630 int h = find_dirty_height(vs, y, last_x, x);
631 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
632 n_rectangles++;
633 }
634 }
635 vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
636 vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
637 vnc_flush(vs);
638
639 }
bellard24236862006-04-30 21:28:36 +0000640
balroga0ecfb72008-01-13 23:51:53 +0000641 if (vs->csock != -1) {
642 qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
bellard24236862006-04-30 21:28:36 +0000643 }
bellard24236862006-04-30 21:28:36 +0000644
bellard24236862006-04-30 21:28:36 +0000645}
646
647static int vnc_listen_poll(void *opaque)
648{
649 VncState *vs = opaque;
650 if (vs->csock == -1)
651 return 1;
652 return 0;
653}
654
655static void buffer_reserve(Buffer *buffer, size_t len)
656{
657 if ((buffer->capacity - buffer->offset) < len) {
658 buffer->capacity += (len + 1024);
ths2137b4c2008-08-06 08:37:17 +0000659 buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
bellard24236862006-04-30 21:28:36 +0000660 if (buffer->buffer == NULL) {
661 fprintf(stderr, "vnc: out of memory\n");
662 exit(1);
663 }
664 }
665}
666
667static int buffer_empty(Buffer *buffer)
668{
669 return buffer->offset == 0;
670}
671
ths60fe76f2007-12-16 03:02:09 +0000672static uint8_t *buffer_end(Buffer *buffer)
bellard24236862006-04-30 21:28:36 +0000673{
674 return buffer->buffer + buffer->offset;
675}
676
677static void buffer_reset(Buffer *buffer)
678{
679 buffer->offset = 0;
680}
681
682static void buffer_append(Buffer *buffer, const void *data, size_t len)
683{
684 memcpy(buffer->buffer + buffer->offset, data, len);
685 buffer->offset += len;
686}
687
malc429a8ed2008-12-01 20:57:48 +0000688/* audio */
689static void audio_capture_notify(void *opaque, audcnotification_e cmd)
690{
691 VncState *vs = opaque;
692
693 switch (cmd) {
694 case AUD_CNOTIFY_DISABLE:
695 vnc_write_u8(vs, 255);
696 vnc_write_u8(vs, 1);
697 vnc_write_u16(vs, 0);
698 vnc_flush(vs);
699 break;
700
701 case AUD_CNOTIFY_ENABLE:
702 vnc_write_u8(vs, 255);
703 vnc_write_u8(vs, 1);
704 vnc_write_u16(vs, 1);
705 vnc_flush(vs);
706 break;
707 }
708}
709
710static void audio_capture_destroy(void *opaque)
711{
712}
713
714static void audio_capture(void *opaque, void *buf, int size)
715{
716 VncState *vs = opaque;
717
718 vnc_write_u8(vs, 255);
719 vnc_write_u8(vs, 1);
720 vnc_write_u16(vs, 2);
721 vnc_write_u32(vs, size);
722 vnc_write(vs, buf, size);
723 vnc_flush(vs);
724}
725
726static void audio_add(VncState *vs)
727{
728 struct audio_capture_ops ops;
729
730 if (vs->audio_cap) {
731 term_printf ("audio already running\n");
732 return;
733 }
734
735 ops.notify = audio_capture_notify;
736 ops.destroy = audio_capture_destroy;
737 ops.capture = audio_capture;
738
739 vs->audio_cap = AUD_add_capture(NULL, &vs->as, &ops, vs);
740 if (!vs->audio_cap) {
741 term_printf ("Failed to add audio capture\n");
742 }
743}
744
745static void audio_del(VncState *vs)
746{
747 if (vs->audio_cap) {
748 AUD_del_capture(vs->audio_cap, vs);
749 vs->audio_cap = NULL;
750 }
751}
752
bellard6ca957f2006-04-30 22:53:25 +0000753static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
bellard24236862006-04-30 21:28:36 +0000754{
755 if (ret == 0 || ret == -1) {
balrogea01e5f2008-04-24 23:40:55 +0000756 if (ret == -1) {
757 switch (last_errno) {
758 case EINTR:
759 case EAGAIN:
760#ifdef _WIN32
761 case WSAEWOULDBLOCK:
762#endif
763 return 0;
764 default:
765 break;
766 }
767 }
bellard24236862006-04-30 21:28:36 +0000768
ths8d5d2d42007-08-25 01:37:51 +0000769 VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0);
bellard24236862006-04-30 21:28:36 +0000770 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
bellard6ca957f2006-04-30 22:53:25 +0000771 closesocket(vs->csock);
bellard24236862006-04-30 21:28:36 +0000772 vs->csock = -1;
aliguoribcfad702008-08-21 20:08:55 +0000773 vs->ds->idle = 1;
bellard24236862006-04-30 21:28:36 +0000774 buffer_reset(&vs->input);
775 buffer_reset(&vs->output);
776 vs->need_update = 0;
blueswir1eb38c522008-09-06 17:47:39 +0000777#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000778 if (vs->tls_session) {
779 gnutls_deinit(vs->tls_session);
780 vs->tls_session = NULL;
781 }
782 vs->wiremode = VNC_WIREMODE_CLEAR;
783#endif /* CONFIG_VNC_TLS */
malc429a8ed2008-12-01 20:57:48 +0000784 audio_del(vs);
bellard24236862006-04-30 21:28:36 +0000785 return 0;
786 }
787 return ret;
788}
789
790static void vnc_client_error(VncState *vs)
791{
bellard6ca957f2006-04-30 22:53:25 +0000792 vnc_client_io_error(vs, -1, EINVAL);
bellard24236862006-04-30 21:28:36 +0000793}
794
795static void vnc_client_write(void *opaque)
796{
bellardceb5caa2006-05-03 21:18:59 +0000797 long ret;
bellard24236862006-04-30 21:28:36 +0000798 VncState *vs = opaque;
799
blueswir1eb38c522008-09-06 17:47:39 +0000800#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000801 if (vs->tls_session) {
802 ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset);
803 if (ret < 0) {
804 if (ret == GNUTLS_E_AGAIN)
805 errno = EAGAIN;
806 else
807 errno = EIO;
808 ret = -1;
809 }
810 } else
811#endif /* CONFIG_VNC_TLS */
812 ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
bellard6ca957f2006-04-30 22:53:25 +0000813 ret = vnc_client_io_error(vs, ret, socket_error());
bellard24236862006-04-30 21:28:36 +0000814 if (!ret)
815 return;
816
817 memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
818 vs->output.offset -= ret;
819
820 if (vs->output.offset == 0) {
821 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
822 }
823}
824
825static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
826{
827 vs->read_handler = func;
828 vs->read_handler_expect = expecting;
829}
830
831static void vnc_client_read(void *opaque)
832{
833 VncState *vs = opaque;
bellardceb5caa2006-05-03 21:18:59 +0000834 long ret;
bellard24236862006-04-30 21:28:36 +0000835
836 buffer_reserve(&vs->input, 4096);
837
blueswir1eb38c522008-09-06 17:47:39 +0000838#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000839 if (vs->tls_session) {
840 ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096);
841 if (ret < 0) {
842 if (ret == GNUTLS_E_AGAIN)
843 errno = EAGAIN;
844 else
845 errno = EIO;
846 ret = -1;
847 }
848 } else
849#endif /* CONFIG_VNC_TLS */
850 ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
bellard6ca957f2006-04-30 22:53:25 +0000851 ret = vnc_client_io_error(vs, ret, socket_error());
bellard24236862006-04-30 21:28:36 +0000852 if (!ret)
853 return;
854
855 vs->input.offset += ret;
856
857 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
858 size_t len = vs->read_handler_expect;
859 int ret;
860
861 ret = vs->read_handler(vs, vs->input.buffer, len);
862 if (vs->csock == -1)
863 return;
864
865 if (!ret) {
866 memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
867 vs->input.offset -= len;
868 } else {
869 vs->read_handler_expect = ret;
870 }
871 }
872}
873
874static void vnc_write(VncState *vs, const void *data, size_t len)
875{
876 buffer_reserve(&vs->output, len);
877
878 if (buffer_empty(&vs->output)) {
879 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
880 }
881
882 buffer_append(&vs->output, data, len);
883}
884
885static void vnc_write_s32(VncState *vs, int32_t value)
886{
887 vnc_write_u32(vs, *(uint32_t *)&value);
888}
889
890static void vnc_write_u32(VncState *vs, uint32_t value)
891{
892 uint8_t buf[4];
893
894 buf[0] = (value >> 24) & 0xFF;
895 buf[1] = (value >> 16) & 0xFF;
896 buf[2] = (value >> 8) & 0xFF;
897 buf[3] = value & 0xFF;
898
899 vnc_write(vs, buf, 4);
900}
901
902static void vnc_write_u16(VncState *vs, uint16_t value)
903{
bellard64f5a132006-08-24 20:36:44 +0000904 uint8_t buf[2];
bellard24236862006-04-30 21:28:36 +0000905
906 buf[0] = (value >> 8) & 0xFF;
907 buf[1] = value & 0xFF;
908
909 vnc_write(vs, buf, 2);
910}
911
912static void vnc_write_u8(VncState *vs, uint8_t value)
913{
914 vnc_write(vs, (char *)&value, 1);
915}
916
917static void vnc_flush(VncState *vs)
918{
919 if (vs->output.offset)
920 vnc_client_write(vs);
921}
922
bellard64f5a132006-08-24 20:36:44 +0000923static uint8_t read_u8(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +0000924{
925 return data[offset];
926}
927
bellard64f5a132006-08-24 20:36:44 +0000928static uint16_t read_u16(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +0000929{
930 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
931}
932
bellard64f5a132006-08-24 20:36:44 +0000933static int32_t read_s32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +0000934{
935 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
936 (data[offset + 2] << 8) | data[offset + 3]);
937}
938
bellard64f5a132006-08-24 20:36:44 +0000939static uint32_t read_u32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +0000940{
941 return ((data[offset] << 24) | (data[offset + 1] << 16) |
942 (data[offset + 2] << 8) | data[offset + 3]);
943}
944
blueswir1eb38c522008-09-06 17:47:39 +0000945#ifdef CONFIG_VNC_TLS
pbrook9596ebb2007-11-18 01:44:38 +0000946static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
947 const void *data,
948 size_t len) {
ths8d5d2d42007-08-25 01:37:51 +0000949 struct VncState *vs = (struct VncState *)transport;
950 int ret;
951
952 retry:
953 ret = send(vs->csock, data, len, 0);
954 if (ret < 0) {
955 if (errno == EINTR)
956 goto retry;
957 return -1;
958 }
959 return ret;
960}
961
962
pbrook9596ebb2007-11-18 01:44:38 +0000963static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
964 void *data,
965 size_t len) {
ths8d5d2d42007-08-25 01:37:51 +0000966 struct VncState *vs = (struct VncState *)transport;
967 int ret;
968
969 retry:
970 ret = recv(vs->csock, data, len, 0);
971 if (ret < 0) {
972 if (errno == EINTR)
973 goto retry;
974 return -1;
975 }
976 return ret;
977}
978#endif /* CONFIG_VNC_TLS */
979
ths60fe76f2007-12-16 03:02:09 +0000980static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
bellard24236862006-04-30 21:28:36 +0000981{
982}
983
bellard564c3372007-02-05 20:14:10 +0000984static void check_pointer_type_change(VncState *vs, int absolute)
985{
986 if (vs->has_pointer_type_change && vs->absolute != absolute) {
987 vnc_write_u8(vs, 0);
988 vnc_write_u8(vs, 0);
989 vnc_write_u16(vs, 1);
990 vnc_framebuffer_update(vs, absolute, 0,
aliguori0e1f5a02008-11-24 19:29:13 +0000991 ds_get_width(vs->ds), ds_get_height(vs->ds), -257);
bellard564c3372007-02-05 20:14:10 +0000992 vnc_flush(vs);
993 }
994 vs->absolute = absolute;
995}
996
bellard24236862006-04-30 21:28:36 +0000997static void pointer_event(VncState *vs, int button_mask, int x, int y)
998{
999 int buttons = 0;
1000 int dz = 0;
1001
1002 if (button_mask & 0x01)
1003 buttons |= MOUSE_EVENT_LBUTTON;
1004 if (button_mask & 0x02)
1005 buttons |= MOUSE_EVENT_MBUTTON;
1006 if (button_mask & 0x04)
1007 buttons |= MOUSE_EVENT_RBUTTON;
1008 if (button_mask & 0x08)
1009 dz = -1;
1010 if (button_mask & 0x10)
1011 dz = 1;
bellard564c3372007-02-05 20:14:10 +00001012
1013 if (vs->absolute) {
aliguori0e1f5a02008-11-24 19:29:13 +00001014 kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
1015 y * 0x7FFF / (ds_get_height(vs->ds) - 1),
bellard24236862006-04-30 21:28:36 +00001016 dz, buttons);
bellard564c3372007-02-05 20:14:10 +00001017 } else if (vs->has_pointer_type_change) {
1018 x -= 0x7FFF;
1019 y -= 0x7FFF;
1020
1021 kbd_mouse_event(x, y, dz, buttons);
bellard24236862006-04-30 21:28:36 +00001022 } else {
bellard564c3372007-02-05 20:14:10 +00001023 if (vs->last_x != -1)
1024 kbd_mouse_event(x - vs->last_x,
1025 y - vs->last_y,
1026 dz, buttons);
1027 vs->last_x = x;
1028 vs->last_y = y;
bellard24236862006-04-30 21:28:36 +00001029 }
bellard564c3372007-02-05 20:14:10 +00001030
1031 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001032}
1033
bellard64f5a132006-08-24 20:36:44 +00001034static void reset_keys(VncState *vs)
1035{
1036 int i;
1037 for(i = 0; i < 256; i++) {
1038 if (vs->modifiers_state[i]) {
1039 if (i & 0x80)
1040 kbd_put_keycode(0xe0);
1041 kbd_put_keycode(i | 0x80);
1042 vs->modifiers_state[i] = 0;
1043 }
1044 }
1045}
1046
balroga528b802007-10-30 22:38:53 +00001047static void press_key(VncState *vs, int keysym)
1048{
1049 kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) & 0x7f);
1050 kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80);
1051}
1052
aliguori9ca313a2008-08-23 23:27:37 +00001053static void do_key_event(VncState *vs, int down, int keycode, int sym)
bellard24236862006-04-30 21:28:36 +00001054{
bellard64f5a132006-08-24 20:36:44 +00001055 /* QEMU console switch */
1056 switch(keycode) {
1057 case 0x2a: /* Left Shift */
1058 case 0x36: /* Right Shift */
1059 case 0x1d: /* Left CTRL */
1060 case 0x9d: /* Right CTRL */
1061 case 0x38: /* Left ALT */
1062 case 0xb8: /* Right ALT */
1063 if (down)
1064 vs->modifiers_state[keycode] = 1;
1065 else
1066 vs->modifiers_state[keycode] = 0;
1067 break;
ths5fafdf22007-09-16 21:08:06 +00001068 case 0x02 ... 0x0a: /* '1' to '9' keys */
bellard64f5a132006-08-24 20:36:44 +00001069 if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1070 /* Reset the modifiers sent to the current console */
1071 reset_keys(vs);
1072 console_select(keycode - 0x02);
1073 return;
1074 }
1075 break;
balrog4d3b6f62008-02-10 16:33:14 +00001076 case 0x3a: /* CapsLock */
balroga528b802007-10-30 22:38:53 +00001077 case 0x45: /* NumLock */
1078 if (!down)
1079 vs->modifiers_state[keycode] ^= 1;
1080 break;
1081 }
1082
1083 if (keycode_is_keypad(vs->kbd_layout, keycode)) {
1084 /* If the numlock state needs to change then simulate an additional
1085 keypress before sending this one. This will happen if the user
1086 toggles numlock away from the VNC window.
1087 */
1088 if (keysym_is_numlock(vs->kbd_layout, sym & 0xFFFF)) {
1089 if (!vs->modifiers_state[0x45]) {
1090 vs->modifiers_state[0x45] = 1;
1091 press_key(vs, 0xff7f);
1092 }
1093 } else {
1094 if (vs->modifiers_state[0x45]) {
1095 vs->modifiers_state[0x45] = 0;
1096 press_key(vs, 0xff7f);
1097 }
1098 }
bellard64f5a132006-08-24 20:36:44 +00001099 }
bellard24236862006-04-30 21:28:36 +00001100
bellard64f5a132006-08-24 20:36:44 +00001101 if (is_graphic_console()) {
1102 if (keycode & 0x80)
1103 kbd_put_keycode(0xe0);
1104 if (down)
1105 kbd_put_keycode(keycode & 0x7f);
1106 else
1107 kbd_put_keycode(keycode | 0x80);
1108 } else {
1109 /* QEMU console emulation */
1110 if (down) {
1111 switch (keycode) {
1112 case 0x2a: /* Left Shift */
1113 case 0x36: /* Right Shift */
1114 case 0x1d: /* Left CTRL */
1115 case 0x9d: /* Right CTRL */
1116 case 0x38: /* Left ALT */
1117 case 0xb8: /* Right ALT */
1118 break;
1119 case 0xc8:
1120 kbd_put_keysym(QEMU_KEY_UP);
1121 break;
1122 case 0xd0:
1123 kbd_put_keysym(QEMU_KEY_DOWN);
1124 break;
1125 case 0xcb:
1126 kbd_put_keysym(QEMU_KEY_LEFT);
1127 break;
1128 case 0xcd:
1129 kbd_put_keysym(QEMU_KEY_RIGHT);
1130 break;
1131 case 0xd3:
1132 kbd_put_keysym(QEMU_KEY_DELETE);
1133 break;
1134 case 0xc7:
1135 kbd_put_keysym(QEMU_KEY_HOME);
1136 break;
1137 case 0xcf:
1138 kbd_put_keysym(QEMU_KEY_END);
1139 break;
1140 case 0xc9:
1141 kbd_put_keysym(QEMU_KEY_PAGEUP);
1142 break;
1143 case 0xd1:
1144 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1145 break;
1146 default:
1147 kbd_put_keysym(sym);
1148 break;
1149 }
1150 }
1151 }
bellard24236862006-04-30 21:28:36 +00001152}
1153
bellardbdbd7672006-05-01 21:44:22 +00001154static void key_event(VncState *vs, int down, uint32_t sym)
1155{
aliguori9ca313a2008-08-23 23:27:37 +00001156 int keycode;
1157
balroga528b802007-10-30 22:38:53 +00001158 if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
bellardbdbd7672006-05-01 21:44:22 +00001159 sym = sym - 'A' + 'a';
aliguori9ca313a2008-08-23 23:27:37 +00001160
1161 keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
1162 do_key_event(vs, down, keycode, sym);
1163}
1164
1165static void ext_key_event(VncState *vs, int down,
1166 uint32_t sym, uint16_t keycode)
1167{
1168 /* if the user specifies a keyboard layout, always use it */
1169 if (keyboard_layout)
1170 key_event(vs, down, sym);
1171 else
1172 do_key_event(vs, down, keycode, sym);
bellardbdbd7672006-05-01 21:44:22 +00001173}
1174
bellard24236862006-04-30 21:28:36 +00001175static void framebuffer_update_request(VncState *vs, int incremental,
1176 int x_position, int y_position,
1177 int w, int h)
1178{
aliguori0e1f5a02008-11-24 19:29:13 +00001179 if (x_position > ds_get_width(vs->ds))
1180 x_position = ds_get_width(vs->ds);
1181 if (y_position > ds_get_height(vs->ds))
1182 y_position = ds_get_height(vs->ds);
1183 if (x_position + w >= ds_get_width(vs->ds))
1184 w = ds_get_width(vs->ds) - x_position;
1185 if (y_position + h >= ds_get_height(vs->ds))
1186 h = ds_get_height(vs->ds) - y_position;
thscf2d3852007-04-29 01:53:20 +00001187
bellard24236862006-04-30 21:28:36 +00001188 int i;
1189 vs->need_update = 1;
1190 if (!incremental) {
aliguori0e1f5a02008-11-24 19:29:13 +00001191 char *old_row = vs->old_data + y_position * ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +00001192
1193 for (i = 0; i < h; i++) {
ths5fafdf22007-09-16 21:08:06 +00001194 vnc_set_bits(vs->dirty_row[y_position + i],
aliguori0e1f5a02008-11-24 19:29:13 +00001195 (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
1196 memset(old_row, 42, ds_get_width(vs->ds) * vs->depth);
1197 old_row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +00001198 }
1199 }
1200}
1201
aliguori9ca313a2008-08-23 23:27:37 +00001202static void send_ext_key_event_ack(VncState *vs)
1203{
1204 vnc_write_u8(vs, 0);
1205 vnc_write_u8(vs, 0);
1206 vnc_write_u16(vs, 1);
aliguori0e1f5a02008-11-24 19:29:13 +00001207 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), -258);
aliguori9ca313a2008-08-23 23:27:37 +00001208 vnc_flush(vs);
1209}
1210
malc429a8ed2008-12-01 20:57:48 +00001211static void send_ext_audio_ack(VncState *vs)
1212{
1213 vnc_write_u8(vs, 0);
1214 vnc_write_u8(vs, 0);
1215 vnc_write_u16(vs, 1);
1216 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), -259);
1217 vnc_flush(vs);
1218}
1219
bellard24236862006-04-30 21:28:36 +00001220static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1221{
1222 int i;
1223
1224 vs->has_hextile = 0;
1225 vs->has_resize = 0;
bellard564c3372007-02-05 20:14:10 +00001226 vs->has_pointer_type_change = 0;
aliguorica4cca42008-09-15 16:05:16 +00001227 vs->has_WMVi = 0;
bellard564c3372007-02-05 20:14:10 +00001228 vs->absolute = -1;
bellard24236862006-04-30 21:28:36 +00001229 vs->ds->dpy_copy = NULL;
1230
1231 for (i = n_encodings - 1; i >= 0; i--) {
1232 switch (encodings[i]) {
1233 case 0: /* Raw */
1234 vs->has_hextile = 0;
1235 break;
1236 case 1: /* CopyRect */
1237 vs->ds->dpy_copy = vnc_copy;
1238 break;
1239 case 5: /* Hextile */
1240 vs->has_hextile = 1;
1241 break;
1242 case -223: /* DesktopResize */
1243 vs->has_resize = 1;
1244 break;
bellard564c3372007-02-05 20:14:10 +00001245 case -257:
1246 vs->has_pointer_type_change = 1;
1247 break;
aliguori9ca313a2008-08-23 23:27:37 +00001248 case -258:
1249 send_ext_key_event_ack(vs);
1250 break;
malc429a8ed2008-12-01 20:57:48 +00001251 case -259:
1252 send_ext_audio_ack(vs);
1253 break;
aliguorica4cca42008-09-15 16:05:16 +00001254 case 0x574D5669:
1255 vs->has_WMVi = 1;
1256 break;
bellard24236862006-04-30 21:28:36 +00001257 default:
1258 break;
1259 }
1260 }
bellard564c3372007-02-05 20:14:10 +00001261
1262 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001263}
1264
1265static void set_pixel_format(VncState *vs,
1266 int bits_per_pixel, int depth,
1267 int big_endian_flag, int true_color_flag,
1268 int red_max, int green_max, int blue_max,
1269 int red_shift, int green_shift, int blue_shift)
1270{
bellard35127792006-05-14 18:11:49 +00001271 int host_big_endian_flag;
bellard24236862006-04-30 21:28:36 +00001272
bellard35127792006-05-14 18:11:49 +00001273#ifdef WORDS_BIGENDIAN
1274 host_big_endian_flag = 1;
1275#else
1276 host_big_endian_flag = 0;
1277#endif
1278 if (!true_color_flag) {
1279 fail:
bellard24236862006-04-30 21:28:36 +00001280 vnc_client_error(vs);
bellard35127792006-05-14 18:11:49 +00001281 return;
1282 }
ths5fafdf22007-09-16 21:08:06 +00001283 if (bits_per_pixel == 32 &&
aliguori7eac3a82008-09-15 16:03:41 +00001284 bits_per_pixel == vs->depth * 8 &&
bellard35127792006-05-14 18:11:49 +00001285 host_big_endian_flag == big_endian_flag &&
1286 red_max == 0xff && green_max == 0xff && blue_max == 0xff &&
1287 red_shift == 16 && green_shift == 8 && blue_shift == 0) {
1288 vs->depth = 4;
1289 vs->write_pixels = vnc_write_pixels_copy;
1290 vs->send_hextile_tile = send_hextile_tile_32;
ths5fafdf22007-09-16 21:08:06 +00001291 } else
1292 if (bits_per_pixel == 16 &&
aliguori7eac3a82008-09-15 16:03:41 +00001293 bits_per_pixel == vs->depth * 8 &&
bellard35127792006-05-14 18:11:49 +00001294 host_big_endian_flag == big_endian_flag &&
1295 red_max == 31 && green_max == 63 && blue_max == 31 &&
1296 red_shift == 11 && green_shift == 5 && blue_shift == 0) {
1297 vs->depth = 2;
1298 vs->write_pixels = vnc_write_pixels_copy;
1299 vs->send_hextile_tile = send_hextile_tile_16;
ths5fafdf22007-09-16 21:08:06 +00001300 } else
1301 if (bits_per_pixel == 8 &&
aliguori7eac3a82008-09-15 16:03:41 +00001302 bits_per_pixel == vs->depth * 8 &&
bellard35127792006-05-14 18:11:49 +00001303 red_max == 7 && green_max == 7 && blue_max == 3 &&
1304 red_shift == 5 && green_shift == 2 && blue_shift == 0) {
1305 vs->depth = 1;
1306 vs->write_pixels = vnc_write_pixels_copy;
1307 vs->send_hextile_tile = send_hextile_tile_8;
ths5fafdf22007-09-16 21:08:06 +00001308 } else
bellard35127792006-05-14 18:11:49 +00001309 {
1310 /* generic and slower case */
1311 if (bits_per_pixel != 8 &&
1312 bits_per_pixel != 16 &&
1313 bits_per_pixel != 32)
1314 goto fail;
aliguori7eac3a82008-09-15 16:03:41 +00001315 if (vs->depth == 4) {
1316 vs->send_hextile_tile = send_hextile_tile_generic_32;
1317 } else if (vs->depth == 2) {
1318 vs->send_hextile_tile = send_hextile_tile_generic_16;
1319 } else {
1320 vs->send_hextile_tile = send_hextile_tile_generic_8;
1321 }
1322
bellard35127792006-05-14 18:11:49 +00001323 vs->pix_big_endian = big_endian_flag;
1324 vs->write_pixels = vnc_write_pixels_generic;
bellard35127792006-05-14 18:11:49 +00001325 }
bellard24236862006-04-30 21:28:36 +00001326
aliguori7eac3a82008-09-15 16:03:41 +00001327 vs->client_red_shift = red_shift;
1328 vs->client_red_max = red_max;
1329 vs->client_green_shift = green_shift;
1330 vs->client_green_max = green_max;
1331 vs->client_blue_shift = blue_shift;
1332 vs->client_blue_max = blue_max;
1333 vs->pix_bpp = bits_per_pixel / 8;
bellard24236862006-04-30 21:28:36 +00001334
1335 vga_hw_invalidate();
1336 vga_hw_update();
1337}
1338
aliguorica4cca42008-09-15 16:05:16 +00001339static void pixel_format_message (VncState *vs) {
1340 char pad[3] = { 0, 0, 0 };
1341
1342 vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */
1343 if (vs->depth == 4) vnc_write_u8(vs, 24); /* depth */
1344 else vnc_write_u8(vs, vs->depth * 8); /* depth */
1345
1346#ifdef WORDS_BIGENDIAN
1347 vnc_write_u8(vs, 1); /* big-endian-flag */
1348#else
1349 vnc_write_u8(vs, 0); /* big-endian-flag */
1350#endif
1351 vnc_write_u8(vs, 1); /* true-color-flag */
1352 if (vs->depth == 4) {
1353 vnc_write_u16(vs, 0xFF); /* red-max */
1354 vnc_write_u16(vs, 0xFF); /* green-max */
1355 vnc_write_u16(vs, 0xFF); /* blue-max */
1356 vnc_write_u8(vs, 16); /* red-shift */
1357 vnc_write_u8(vs, 8); /* green-shift */
1358 vnc_write_u8(vs, 0); /* blue-shift */
1359 vs->send_hextile_tile = send_hextile_tile_32;
1360 } else if (vs->depth == 2) {
1361 vnc_write_u16(vs, 31); /* red-max */
1362 vnc_write_u16(vs, 63); /* green-max */
1363 vnc_write_u16(vs, 31); /* blue-max */
1364 vnc_write_u8(vs, 11); /* red-shift */
1365 vnc_write_u8(vs, 5); /* green-shift */
1366 vnc_write_u8(vs, 0); /* blue-shift */
1367 vs->send_hextile_tile = send_hextile_tile_16;
1368 } else if (vs->depth == 1) {
1369 /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */
1370 vnc_write_u16(vs, 7); /* red-max */
1371 vnc_write_u16(vs, 7); /* green-max */
1372 vnc_write_u16(vs, 3); /* blue-max */
1373 vnc_write_u8(vs, 5); /* red-shift */
1374 vnc_write_u8(vs, 2); /* green-shift */
1375 vnc_write_u8(vs, 0); /* blue-shift */
1376 vs->send_hextile_tile = send_hextile_tile_8;
1377 }
1378 vs->client_red_max = vs->server_red_max;
1379 vs->client_green_max = vs->server_green_max;
1380 vs->client_blue_max = vs->server_blue_max;
1381 vs->client_red_shift = vs->server_red_shift;
1382 vs->client_green_shift = vs->server_green_shift;
1383 vs->client_blue_shift = vs->server_blue_shift;
1384 vs->pix_bpp = vs->depth * 8;
1385 vs->write_pixels = vnc_write_pixels_copy;
1386
1387 vnc_write(vs, pad, 3); /* padding */
1388}
1389
aliguori7eac3a82008-09-15 16:03:41 +00001390static void vnc_colordepth(DisplayState *ds, int depth)
1391{
1392 int host_big_endian_flag;
1393 struct VncState *vs = ds->opaque;
1394
1395 switch (depth) {
1396 case 24:
1397 if (ds->depth == 32) return;
1398 depth = 32;
1399 break;
1400 case 15:
1401 case 8:
1402 case 0:
1403 return;
1404 default:
1405 break;
1406 }
1407
1408#ifdef WORDS_BIGENDIAN
1409 host_big_endian_flag = 1;
1410#else
1411 host_big_endian_flag = 0;
1412#endif
1413
1414 switch (depth) {
1415 case 8:
1416 vs->depth = depth / 8;
1417 vs->server_red_max = 7;
1418 vs->server_green_max = 7;
1419 vs->server_blue_max = 3;
1420 vs->server_red_shift = 5;
1421 vs->server_green_shift = 2;
1422 vs->server_blue_shift = 0;
1423 break;
1424 case 16:
1425 vs->depth = depth / 8;
1426 vs->server_red_max = 31;
1427 vs->server_green_max = 63;
1428 vs->server_blue_max = 31;
1429 vs->server_red_shift = 11;
1430 vs->server_green_shift = 5;
1431 vs->server_blue_shift = 0;
1432 break;
1433 case 32:
1434 vs->depth = 4;
1435 vs->server_red_max = 255;
1436 vs->server_green_max = 255;
1437 vs->server_blue_max = 255;
1438 vs->server_red_shift = 16;
1439 vs->server_green_shift = 8;
1440 vs->server_blue_shift = 0;
1441 break;
1442 default:
1443 return;
1444 }
1445
aliguorica4cca42008-09-15 16:05:16 +00001446 if (vs->csock != -1 && vs->has_WMVi) {
1447 /* Sending a WMVi message to notify the client*/
1448 vnc_write_u8(vs, 0); /* msg id */
1449 vnc_write_u8(vs, 0);
1450 vnc_write_u16(vs, 1); /* number of rects */
1451 vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, 0x574D5669);
1452 pixel_format_message(vs);
1453 vnc_flush(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001454 } else {
aliguorica4cca42008-09-15 16:05:16 +00001455 if (vs->pix_bpp == 4 && vs->depth == 4 &&
1456 host_big_endian_flag == vs->pix_big_endian &&
1457 vs->client_red_max == 0xff && vs->client_green_max == 0xff && vs->client_blue_max == 0xff &&
1458 vs->client_red_shift == 16 && vs->client_green_shift == 8 && vs->client_blue_shift == 0) {
1459 vs->write_pixels = vnc_write_pixels_copy;
1460 vs->send_hextile_tile = send_hextile_tile_32;
1461 } else if (vs->pix_bpp == 2 && vs->depth == 2 &&
1462 host_big_endian_flag == vs->pix_big_endian &&
1463 vs->client_red_max == 31 && vs->client_green_max == 63 && vs->client_blue_max == 31 &&
1464 vs->client_red_shift == 11 && vs->client_green_shift == 5 && vs->client_blue_shift == 0) {
1465 vs->write_pixels = vnc_write_pixels_copy;
1466 vs->send_hextile_tile = send_hextile_tile_16;
1467 } else if (vs->pix_bpp == 1 && vs->depth == 1 &&
1468 host_big_endian_flag == vs->pix_big_endian &&
1469 vs->client_red_max == 7 && vs->client_green_max == 7 && vs->client_blue_max == 3 &&
1470 vs->client_red_shift == 5 && vs->client_green_shift == 2 && vs->client_blue_shift == 0) {
1471 vs->write_pixels = vnc_write_pixels_copy;
1472 vs->send_hextile_tile = send_hextile_tile_8;
aliguori7eac3a82008-09-15 16:03:41 +00001473 } else {
aliguorica4cca42008-09-15 16:05:16 +00001474 if (vs->depth == 4) {
1475 vs->send_hextile_tile = send_hextile_tile_generic_32;
1476 } else if (vs->depth == 2) {
1477 vs->send_hextile_tile = send_hextile_tile_generic_16;
1478 } else {
1479 vs->send_hextile_tile = send_hextile_tile_generic_8;
1480 }
1481 vs->write_pixels = vnc_write_pixels_generic;
aliguori7eac3a82008-09-15 16:03:41 +00001482 }
aliguori7eac3a82008-09-15 16:03:41 +00001483 }
1484}
1485
ths60fe76f2007-12-16 03:02:09 +00001486static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001487{
1488 int i;
1489 uint16_t limit;
1490
1491 switch (data[0]) {
1492 case 0:
1493 if (len == 1)
1494 return 20;
1495
1496 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
1497 read_u8(data, 6), read_u8(data, 7),
1498 read_u16(data, 8), read_u16(data, 10),
1499 read_u16(data, 12), read_u8(data, 14),
1500 read_u8(data, 15), read_u8(data, 16));
1501 break;
1502 case 2:
1503 if (len == 1)
1504 return 4;
1505
aliguori69dd5c92008-12-22 21:06:23 +00001506 if (len == 4) {
1507 limit = read_u16(data, 2);
1508 if (limit > 0)
1509 return 4 + (limit * 4);
1510 } else
1511 limit = read_u16(data, 2);
bellard24236862006-04-30 21:28:36 +00001512
bellard24236862006-04-30 21:28:36 +00001513 for (i = 0; i < limit; i++) {
1514 int32_t val = read_s32(data, 4 + (i * 4));
1515 memcpy(data + 4 + (i * 4), &val, sizeof(val));
1516 }
1517
1518 set_encodings(vs, (int32_t *)(data + 4), limit);
1519 break;
1520 case 3:
1521 if (len == 1)
1522 return 10;
1523
1524 framebuffer_update_request(vs,
1525 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
1526 read_u16(data, 6), read_u16(data, 8));
1527 break;
1528 case 4:
1529 if (len == 1)
1530 return 8;
1531
1532 key_event(vs, read_u8(data, 1), read_u32(data, 4));
1533 break;
1534 case 5:
1535 if (len == 1)
1536 return 6;
1537
1538 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
1539 break;
1540 case 6:
1541 if (len == 1)
1542 return 8;
1543
thsbaa76662007-09-13 12:41:42 +00001544 if (len == 8) {
1545 uint32_t dlen = read_u32(data, 4);
1546 if (dlen > 0)
1547 return 8 + dlen;
1548 }
bellard24236862006-04-30 21:28:36 +00001549
1550 client_cut_text(vs, read_u32(data, 4), data + 8);
1551 break;
aliguori9ca313a2008-08-23 23:27:37 +00001552 case 255:
1553 if (len == 1)
1554 return 2;
1555
1556 switch (read_u8(data, 1)) {
1557 case 0:
1558 if (len == 2)
1559 return 12;
1560
1561 ext_key_event(vs, read_u16(data, 2),
1562 read_u32(data, 4), read_u32(data, 8));
1563 break;
malc429a8ed2008-12-01 20:57:48 +00001564 case 1:
1565 if (len == 2)
1566 return 4;
1567
1568 switch (read_u16 (data, 2)) {
1569 case 0:
1570 audio_add(vs);
1571 break;
1572 case 1:
1573 audio_del(vs);
1574 break;
1575 case 2:
1576 if (len == 4)
1577 return 10;
1578 switch (read_u8(data, 4)) {
1579 case 0: vs->as.fmt = AUD_FMT_U8; break;
1580 case 1: vs->as.fmt = AUD_FMT_S8; break;
1581 case 2: vs->as.fmt = AUD_FMT_U16; break;
1582 case 3: vs->as.fmt = AUD_FMT_S16; break;
1583 case 4: vs->as.fmt = AUD_FMT_U32; break;
1584 case 5: vs->as.fmt = AUD_FMT_S32; break;
1585 default:
1586 printf("Invalid audio format %d\n", read_u8(data, 4));
1587 vnc_client_error(vs);
1588 break;
1589 }
1590 vs->as.nchannels = read_u8(data, 5);
1591 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
1592 printf("Invalid audio channel coount %d\n",
1593 read_u8(data, 5));
1594 vnc_client_error(vs);
1595 break;
1596 }
1597 vs->as.freq = read_u32(data, 6);
1598 break;
1599 default:
1600 printf ("Invalid audio message %d\n", read_u8(data, 4));
1601 vnc_client_error(vs);
1602 break;
1603 }
1604 break;
1605
aliguori9ca313a2008-08-23 23:27:37 +00001606 default:
1607 printf("Msg: %d\n", read_u16(data, 0));
1608 vnc_client_error(vs);
1609 break;
1610 }
1611 break;
bellard24236862006-04-30 21:28:36 +00001612 default:
1613 printf("Msg: %d\n", data[0]);
1614 vnc_client_error(vs);
1615 break;
1616 }
ths5fafdf22007-09-16 21:08:06 +00001617
bellard24236862006-04-30 21:28:36 +00001618 vnc_read_when(vs, protocol_client_msg, 1);
1619 return 0;
1620}
1621
ths60fe76f2007-12-16 03:02:09 +00001622static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001623{
thsc35734b2007-03-19 15:17:08 +00001624 char buf[1024];
1625 int size;
bellard24236862006-04-30 21:28:36 +00001626
aliguori0e1f5a02008-11-24 19:29:13 +00001627 vs->width = ds_get_width(vs->ds);
1628 vs->height = ds_get_height(vs->ds);
1629 vnc_write_u16(vs, ds_get_width(vs->ds));
1630 vnc_write_u16(vs, ds_get_height(vs->ds));
bellard24236862006-04-30 21:28:36 +00001631
aliguorica4cca42008-09-15 16:05:16 +00001632 pixel_format_message(vs);
bellard24236862006-04-30 21:28:36 +00001633
thsc35734b2007-03-19 15:17:08 +00001634 if (qemu_name)
1635 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
1636 else
1637 size = snprintf(buf, sizeof(buf), "QEMU");
1638
1639 vnc_write_u32(vs, size);
1640 vnc_write(vs, buf, size);
bellard24236862006-04-30 21:28:36 +00001641 vnc_flush(vs);
1642
1643 vnc_read_when(vs, protocol_client_msg, 1);
1644
1645 return 0;
1646}
1647
ths70848512007-08-25 01:37:05 +00001648static void make_challenge(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001649{
ths70848512007-08-25 01:37:05 +00001650 int i;
bellard24236862006-04-30 21:28:36 +00001651
ths70848512007-08-25 01:37:05 +00001652 srand(time(NULL)+getpid()+getpid()*987654+rand());
bellard24236862006-04-30 21:28:36 +00001653
ths70848512007-08-25 01:37:05 +00001654 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
1655 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
1656}
1657
ths60fe76f2007-12-16 03:02:09 +00001658static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00001659{
ths60fe76f2007-12-16 03:02:09 +00001660 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
ths70848512007-08-25 01:37:05 +00001661 int i, j, pwlen;
ths60fe76f2007-12-16 03:02:09 +00001662 unsigned char key[8];
ths70848512007-08-25 01:37:05 +00001663
1664 if (!vs->password || !vs->password[0]) {
1665 VNC_DEBUG("No password configured on server");
1666 vnc_write_u32(vs, 1); /* Reject auth */
1667 if (vs->minor >= 8) {
1668 static const char err[] = "Authentication failed";
1669 vnc_write_u32(vs, sizeof(err));
1670 vnc_write(vs, err, sizeof(err));
1671 }
1672 vnc_flush(vs);
bellard24236862006-04-30 21:28:36 +00001673 vnc_client_error(vs);
1674 return 0;
1675 }
1676
ths70848512007-08-25 01:37:05 +00001677 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
1678
1679 /* Calculate the expected challenge response */
1680 pwlen = strlen(vs->password);
1681 for (i=0; i<sizeof(key); i++)
1682 key[i] = i<pwlen ? vs->password[i] : 0;
1683 deskey(key, EN0);
1684 for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
1685 des(response+j, response+j);
1686
1687 /* Compare expected vs actual challenge response */
1688 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
1689 VNC_DEBUG("Client challenge reponse did not match\n");
1690 vnc_write_u32(vs, 1); /* Reject auth */
1691 if (vs->minor >= 8) {
1692 static const char err[] = "Authentication failed";
1693 vnc_write_u32(vs, sizeof(err));
1694 vnc_write(vs, err, sizeof(err));
1695 }
1696 vnc_flush(vs);
1697 vnc_client_error(vs);
1698 } else {
1699 VNC_DEBUG("Accepting VNC challenge response\n");
1700 vnc_write_u32(vs, 0); /* Accept auth */
1701 vnc_flush(vs);
1702
1703 vnc_read_when(vs, protocol_client_init, 1);
1704 }
1705 return 0;
1706}
1707
1708static int start_auth_vnc(VncState *vs)
1709{
1710 make_challenge(vs);
1711 /* Send client a 'random' challenge */
1712 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
bellard24236862006-04-30 21:28:36 +00001713 vnc_flush(vs);
1714
ths70848512007-08-25 01:37:05 +00001715 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
1716 return 0;
1717}
1718
ths8d5d2d42007-08-25 01:37:51 +00001719
blueswir1eb38c522008-09-06 17:47:39 +00001720#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00001721#define DH_BITS 1024
1722static gnutls_dh_params_t dh_params;
1723
1724static int vnc_tls_initialize(void)
1725{
1726 static int tlsinitialized = 0;
1727
1728 if (tlsinitialized)
1729 return 1;
1730
1731 if (gnutls_global_init () < 0)
1732 return 0;
1733
1734 /* XXX ought to re-generate diffie-hellmen params periodically */
1735 if (gnutls_dh_params_init (&dh_params) < 0)
1736 return 0;
1737 if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
1738 return 0;
1739
ths234c9bc2008-09-24 15:17:57 +00001740#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
ths8d5d2d42007-08-25 01:37:51 +00001741 gnutls_global_set_log_level(10);
1742 gnutls_global_set_log_function(vnc_debug_gnutls_log);
1743#endif
1744
1745 tlsinitialized = 1;
1746
1747 return 1;
1748}
1749
1750static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
1751{
1752 gnutls_anon_server_credentials anon_cred;
1753 int ret;
1754
1755 if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
1756 VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
1757 return NULL;
1758 }
1759
1760 gnutls_anon_set_server_dh_params(anon_cred, dh_params);
1761
1762 return anon_cred;
1763}
1764
1765
ths6f430242007-08-25 01:39:57 +00001766static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs)
ths3a702692007-08-25 01:38:36 +00001767{
1768 gnutls_certificate_credentials_t x509_cred;
1769 int ret;
ths6f430242007-08-25 01:39:57 +00001770
1771 if (!vs->x509cacert) {
1772 VNC_DEBUG("No CA x509 certificate specified\n");
1773 return NULL;
1774 }
1775 if (!vs->x509cert) {
1776 VNC_DEBUG("No server x509 certificate specified\n");
1777 return NULL;
1778 }
1779 if (!vs->x509key) {
1780 VNC_DEBUG("No server private key specified\n");
1781 return NULL;
1782 }
ths3a702692007-08-25 01:38:36 +00001783
1784 if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
1785 VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
1786 return NULL;
1787 }
ths6f430242007-08-25 01:39:57 +00001788 if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
1789 vs->x509cacert,
1790 GNUTLS_X509_FMT_PEM)) < 0) {
ths3a702692007-08-25 01:38:36 +00001791 VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
1792 gnutls_certificate_free_credentials(x509_cred);
1793 return NULL;
1794 }
1795
ths6f430242007-08-25 01:39:57 +00001796 if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
1797 vs->x509cert,
1798 vs->x509key,
ths3a702692007-08-25 01:38:36 +00001799 GNUTLS_X509_FMT_PEM)) < 0) {
1800 VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
1801 gnutls_certificate_free_credentials(x509_cred);
1802 return NULL;
1803 }
1804
ths6f430242007-08-25 01:39:57 +00001805 if (vs->x509cacrl) {
1806 if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
1807 vs->x509cacrl,
1808 GNUTLS_X509_FMT_PEM)) < 0) {
ths3a702692007-08-25 01:38:36 +00001809 VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
1810 gnutls_certificate_free_credentials(x509_cred);
1811 return NULL;
1812 }
1813 }
1814
1815 gnutls_certificate_set_dh_params (x509_cred, dh_params);
1816
1817 return x509_cred;
1818}
1819
ths469b15c2007-08-25 01:39:10 +00001820static int vnc_validate_certificate(struct VncState *vs)
1821{
1822 int ret;
1823 unsigned int status;
1824 const gnutls_datum_t *certs;
1825 unsigned int nCerts, i;
1826 time_t now;
1827
1828 VNC_DEBUG("Validating client certificate\n");
1829 if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) {
1830 VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
1831 return -1;
1832 }
1833
1834 if ((now = time(NULL)) == ((time_t)-1)) {
1835 return -1;
1836 }
1837
1838 if (status != 0) {
1839 if (status & GNUTLS_CERT_INVALID)
1840 VNC_DEBUG("The certificate is not trusted.\n");
1841
1842 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
1843 VNC_DEBUG("The certificate hasn't got a known issuer.\n");
1844
1845 if (status & GNUTLS_CERT_REVOKED)
1846 VNC_DEBUG("The certificate has been revoked.\n");
1847
1848 if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
1849 VNC_DEBUG("The certificate uses an insecure algorithm\n");
1850
1851 return -1;
1852 } else {
1853 VNC_DEBUG("Certificate is valid!\n");
1854 }
1855
1856 /* Only support x509 for now */
1857 if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509)
1858 return -1;
1859
1860 if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts)))
1861 return -1;
1862
1863 for (i = 0 ; i < nCerts ; i++) {
1864 gnutls_x509_crt_t cert;
1865 VNC_DEBUG ("Checking certificate chain %d\n", i);
1866 if (gnutls_x509_crt_init (&cert) < 0)
1867 return -1;
1868
1869 if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
1870 gnutls_x509_crt_deinit (cert);
1871 return -1;
1872 }
1873
1874 if (gnutls_x509_crt_get_expiration_time (cert) < now) {
1875 VNC_DEBUG("The certificate has expired\n");
1876 gnutls_x509_crt_deinit (cert);
1877 return -1;
1878 }
1879
1880 if (gnutls_x509_crt_get_activation_time (cert) > now) {
1881 VNC_DEBUG("The certificate is not yet activated\n");
1882 gnutls_x509_crt_deinit (cert);
1883 return -1;
1884 }
1885
1886 if (gnutls_x509_crt_get_activation_time (cert) > now) {
1887 VNC_DEBUG("The certificate is not yet activated\n");
1888 gnutls_x509_crt_deinit (cert);
1889 return -1;
1890 }
1891
1892 gnutls_x509_crt_deinit (cert);
1893 }
1894
1895 return 0;
1896}
1897
1898
ths8d5d2d42007-08-25 01:37:51 +00001899static int start_auth_vencrypt_subauth(VncState *vs)
1900{
1901 switch (vs->subauth) {
1902 case VNC_AUTH_VENCRYPT_TLSNONE:
ths3a702692007-08-25 01:38:36 +00001903 case VNC_AUTH_VENCRYPT_X509NONE:
ths8d5d2d42007-08-25 01:37:51 +00001904 VNC_DEBUG("Accept TLS auth none\n");
1905 vnc_write_u32(vs, 0); /* Accept auth completion */
1906 vnc_read_when(vs, protocol_client_init, 1);
1907 break;
1908
1909 case VNC_AUTH_VENCRYPT_TLSVNC:
ths3a702692007-08-25 01:38:36 +00001910 case VNC_AUTH_VENCRYPT_X509VNC:
ths8d5d2d42007-08-25 01:37:51 +00001911 VNC_DEBUG("Start TLS auth VNC\n");
1912 return start_auth_vnc(vs);
1913
1914 default: /* Should not be possible, but just in case */
1915 VNC_DEBUG("Reject auth %d\n", vs->auth);
1916 vnc_write_u8(vs, 1);
1917 if (vs->minor >= 8) {
1918 static const char err[] = "Unsupported authentication type";
1919 vnc_write_u32(vs, sizeof(err));
1920 vnc_write(vs, err, sizeof(err));
1921 }
1922 vnc_client_error(vs);
1923 }
1924
1925 return 0;
1926}
1927
1928static void vnc_handshake_io(void *opaque);
1929
1930static int vnc_continue_handshake(struct VncState *vs) {
1931 int ret;
1932
1933 if ((ret = gnutls_handshake(vs->tls_session)) < 0) {
1934 if (!gnutls_error_is_fatal(ret)) {
1935 VNC_DEBUG("Handshake interrupted (blocking)\n");
1936 if (!gnutls_record_get_direction(vs->tls_session))
1937 qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs);
1938 else
1939 qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs);
1940 return 0;
1941 }
1942 VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
1943 vnc_client_error(vs);
1944 return -1;
1945 }
1946
ths469b15c2007-08-25 01:39:10 +00001947 if (vs->x509verify) {
1948 if (vnc_validate_certificate(vs) < 0) {
1949 VNC_DEBUG("Client verification failed\n");
1950 vnc_client_error(vs);
1951 return -1;
1952 } else {
1953 VNC_DEBUG("Client verification passed\n");
1954 }
1955 }
1956
ths8d5d2d42007-08-25 01:37:51 +00001957 VNC_DEBUG("Handshake done, switching to TLS data mode\n");
1958 vs->wiremode = VNC_WIREMODE_TLS;
1959 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
1960
1961 return start_auth_vencrypt_subauth(vs);
1962}
1963
1964static void vnc_handshake_io(void *opaque) {
1965 struct VncState *vs = (struct VncState *)opaque;
1966
1967 VNC_DEBUG("Handshake IO continue\n");
1968 vnc_continue_handshake(vs);
1969}
1970
ths3a702692007-08-25 01:38:36 +00001971#define NEED_X509_AUTH(vs) \
1972 ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \
1973 (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \
1974 (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
1975
1976
ths8d5d2d42007-08-25 01:37:51 +00001977static int vnc_start_tls(struct VncState *vs) {
1978 static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
1979 static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
1980 static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
ths3a702692007-08-25 01:38:36 +00001981 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 +00001982
1983 VNC_DEBUG("Do TLS setup\n");
1984 if (vnc_tls_initialize() < 0) {
1985 VNC_DEBUG("Failed to init TLS\n");
1986 vnc_client_error(vs);
1987 return -1;
1988 }
1989 if (vs->tls_session == NULL) {
1990 if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) {
1991 vnc_client_error(vs);
1992 return -1;
1993 }
1994
1995 if (gnutls_set_default_priority(vs->tls_session) < 0) {
1996 gnutls_deinit(vs->tls_session);
1997 vs->tls_session = NULL;
1998 vnc_client_error(vs);
1999 return -1;
2000 }
2001
ths3a702692007-08-25 01:38:36 +00002002 if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) {
ths8d5d2d42007-08-25 01:37:51 +00002003 gnutls_deinit(vs->tls_session);
2004 vs->tls_session = NULL;
2005 vnc_client_error(vs);
2006 return -1;
2007 }
2008
2009 if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) {
2010 gnutls_deinit(vs->tls_session);
2011 vs->tls_session = NULL;
2012 vnc_client_error(vs);
2013 return -1;
2014 }
2015
2016 if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) {
2017 gnutls_deinit(vs->tls_session);
2018 vs->tls_session = NULL;
2019 vnc_client_error(vs);
2020 return -1;
2021 }
2022
ths3a702692007-08-25 01:38:36 +00002023 if (NEED_X509_AUTH(vs)) {
ths6f430242007-08-25 01:39:57 +00002024 gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs);
ths3a702692007-08-25 01:38:36 +00002025 if (!x509_cred) {
2026 gnutls_deinit(vs->tls_session);
2027 vs->tls_session = NULL;
2028 vnc_client_error(vs);
2029 return -1;
2030 }
2031 if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
2032 gnutls_deinit(vs->tls_session);
2033 vs->tls_session = NULL;
2034 gnutls_certificate_free_credentials(x509_cred);
2035 vnc_client_error(vs);
2036 return -1;
2037 }
ths469b15c2007-08-25 01:39:10 +00002038 if (vs->x509verify) {
2039 VNC_DEBUG("Requesting a client certificate\n");
2040 gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
2041 }
2042
ths3a702692007-08-25 01:38:36 +00002043 } else {
2044 gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
2045 if (!anon_cred) {
2046 gnutls_deinit(vs->tls_session);
2047 vs->tls_session = NULL;
2048 vnc_client_error(vs);
2049 return -1;
2050 }
2051 if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
2052 gnutls_deinit(vs->tls_session);
2053 vs->tls_session = NULL;
2054 gnutls_anon_free_server_credentials(anon_cred);
2055 vnc_client_error(vs);
2056 return -1;
2057 }
ths8d5d2d42007-08-25 01:37:51 +00002058 }
2059
2060 gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs);
2061 gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push);
2062 gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull);
2063 }
2064
2065 VNC_DEBUG("Start TLS handshake process\n");
2066 return vnc_continue_handshake(vs);
2067}
2068
ths60fe76f2007-12-16 03:02:09 +00002069static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
ths8d5d2d42007-08-25 01:37:51 +00002070{
2071 int auth = read_u32(data, 0);
2072
2073 if (auth != vs->subauth) {
2074 VNC_DEBUG("Rejecting auth %d\n", auth);
2075 vnc_write_u8(vs, 0); /* Reject auth */
2076 vnc_flush(vs);
2077 vnc_client_error(vs);
2078 } else {
2079 VNC_DEBUG("Accepting auth %d, starting handshake\n", auth);
2080 vnc_write_u8(vs, 1); /* Accept auth */
2081 vnc_flush(vs);
2082
2083 if (vnc_start_tls(vs) < 0) {
2084 VNC_DEBUG("Failed to complete TLS\n");
2085 return 0;
2086 }
2087
2088 if (vs->wiremode == VNC_WIREMODE_TLS) {
2089 VNC_DEBUG("Starting VeNCrypt subauth\n");
2090 return start_auth_vencrypt_subauth(vs);
2091 } else {
2092 VNC_DEBUG("TLS handshake blocked\n");
2093 return 0;
2094 }
2095 }
2096 return 0;
2097}
2098
ths60fe76f2007-12-16 03:02:09 +00002099static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
ths8d5d2d42007-08-25 01:37:51 +00002100{
2101 if (data[0] != 0 ||
2102 data[1] != 2) {
2103 VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
2104 vnc_write_u8(vs, 1); /* Reject version */
2105 vnc_flush(vs);
2106 vnc_client_error(vs);
2107 } else {
2108 VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
2109 vnc_write_u8(vs, 0); /* Accept version */
2110 vnc_write_u8(vs, 1); /* Number of sub-auths */
2111 vnc_write_u32(vs, vs->subauth); /* The supported auth */
2112 vnc_flush(vs);
2113 vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
2114 }
2115 return 0;
2116}
2117
2118static int start_auth_vencrypt(VncState *vs)
2119{
2120 /* Send VeNCrypt version 0.2 */
2121 vnc_write_u8(vs, 0);
2122 vnc_write_u8(vs, 2);
2123
2124 vnc_read_when(vs, protocol_client_vencrypt_init, 2);
2125 return 0;
2126}
2127#endif /* CONFIG_VNC_TLS */
2128
ths60fe76f2007-12-16 03:02:09 +00002129static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002130{
2131 /* We only advertise 1 auth scheme at a time, so client
2132 * must pick the one we sent. Verify this */
2133 if (data[0] != vs->auth) { /* Reject auth */
2134 VNC_DEBUG("Reject auth %d\n", (int)data[0]);
2135 vnc_write_u32(vs, 1);
2136 if (vs->minor >= 8) {
2137 static const char err[] = "Authentication failed";
2138 vnc_write_u32(vs, sizeof(err));
2139 vnc_write(vs, err, sizeof(err));
2140 }
2141 vnc_client_error(vs);
2142 } else { /* Accept requested auth */
2143 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
2144 switch (vs->auth) {
2145 case VNC_AUTH_NONE:
2146 VNC_DEBUG("Accept auth none\n");
balroga26c97a2007-10-31 01:58:56 +00002147 if (vs->minor >= 8) {
2148 vnc_write_u32(vs, 0); /* Accept auth completion */
2149 vnc_flush(vs);
2150 }
ths70848512007-08-25 01:37:05 +00002151 vnc_read_when(vs, protocol_client_init, 1);
2152 break;
2153
2154 case VNC_AUTH_VNC:
2155 VNC_DEBUG("Start VNC auth\n");
2156 return start_auth_vnc(vs);
2157
blueswir1eb38c522008-09-06 17:47:39 +00002158#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002159 case VNC_AUTH_VENCRYPT:
2160 VNC_DEBUG("Accept VeNCrypt auth\n");;
2161 return start_auth_vencrypt(vs);
2162#endif /* CONFIG_VNC_TLS */
2163
ths70848512007-08-25 01:37:05 +00002164 default: /* Should not be possible, but just in case */
2165 VNC_DEBUG("Reject auth %d\n", vs->auth);
2166 vnc_write_u8(vs, 1);
2167 if (vs->minor >= 8) {
2168 static const char err[] = "Authentication failed";
2169 vnc_write_u32(vs, sizeof(err));
2170 vnc_write(vs, err, sizeof(err));
2171 }
2172 vnc_client_error(vs);
2173 }
2174 }
2175 return 0;
2176}
2177
ths60fe76f2007-12-16 03:02:09 +00002178static int protocol_version(VncState *vs, uint8_t *version, size_t len)
ths70848512007-08-25 01:37:05 +00002179{
2180 char local[13];
2181
2182 memcpy(local, version, 12);
2183 local[12] = 0;
2184
2185 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
2186 VNC_DEBUG("Malformed protocol version %s\n", local);
2187 vnc_client_error(vs);
2188 return 0;
2189 }
2190 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2191 if (vs->major != 3 ||
2192 (vs->minor != 3 &&
thsb0566f42007-09-30 13:01:15 +00002193 vs->minor != 4 &&
ths70848512007-08-25 01:37:05 +00002194 vs->minor != 5 &&
2195 vs->minor != 7 &&
2196 vs->minor != 8)) {
2197 VNC_DEBUG("Unsupported client version\n");
2198 vnc_write_u32(vs, VNC_AUTH_INVALID);
2199 vnc_flush(vs);
2200 vnc_client_error(vs);
2201 return 0;
2202 }
thsb0566f42007-09-30 13:01:15 +00002203 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
ths70848512007-08-25 01:37:05 +00002204 * as equivalent to v3.3 by servers
2205 */
thsb0566f42007-09-30 13:01:15 +00002206 if (vs->minor == 4 || vs->minor == 5)
ths70848512007-08-25 01:37:05 +00002207 vs->minor = 3;
2208
2209 if (vs->minor == 3) {
2210 if (vs->auth == VNC_AUTH_NONE) {
2211 VNC_DEBUG("Tell client auth none\n");
2212 vnc_write_u32(vs, vs->auth);
2213 vnc_flush(vs);
2214 vnc_read_when(vs, protocol_client_init, 1);
2215 } else if (vs->auth == VNC_AUTH_VNC) {
2216 VNC_DEBUG("Tell client VNC auth\n");
2217 vnc_write_u32(vs, vs->auth);
2218 vnc_flush(vs);
2219 start_auth_vnc(vs);
2220 } else {
2221 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
2222 vnc_write_u32(vs, VNC_AUTH_INVALID);
2223 vnc_flush(vs);
2224 vnc_client_error(vs);
2225 }
2226 } else {
2227 VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
2228 vnc_write_u8(vs, 1); /* num auth */
2229 vnc_write_u8(vs, vs->auth);
2230 vnc_read_when(vs, protocol_client_auth, 1);
2231 vnc_flush(vs);
2232 }
bellard24236862006-04-30 21:28:36 +00002233
2234 return 0;
2235}
2236
balrog3aa3eea2008-02-03 02:54:04 +00002237static void vnc_connect(VncState *vs)
2238{
2239 VNC_DEBUG("New client on socket %d\n", vs->csock);
aliguoribcfad702008-08-21 20:08:55 +00002240 vs->ds->idle = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002241 socket_set_nonblock(vs->csock);
2242 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
2243 vnc_write(vs, "RFB 003.008\n", 12);
2244 vnc_flush(vs);
2245 vnc_read_when(vs, protocol_version, 12);
aliguori0e1f5a02008-11-24 19:29:13 +00002246 memset(vs->old_data, 0, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
balrog3aa3eea2008-02-03 02:54:04 +00002247 memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
2248 vs->has_resize = 0;
2249 vs->has_hextile = 0;
2250 vs->ds->dpy_copy = NULL;
2251 vnc_update_client(vs);
malc53762dd2008-12-01 20:57:52 +00002252 reset_keys(vs);
balrog3aa3eea2008-02-03 02:54:04 +00002253}
2254
bellard24236862006-04-30 21:28:36 +00002255static void vnc_listen_read(void *opaque)
2256{
2257 VncState *vs = opaque;
2258 struct sockaddr_in addr;
2259 socklen_t addrlen = sizeof(addr);
2260
balrog9f60ad52008-01-14 21:45:55 +00002261 /* Catch-up */
2262 vga_hw_update();
2263
bellard24236862006-04-30 21:28:36 +00002264 vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
2265 if (vs->csock != -1) {
balrog3aa3eea2008-02-03 02:54:04 +00002266 vnc_connect(vs);
bellard24236862006-04-30 21:28:36 +00002267 }
2268}
2269
ths71cab5c2007-08-25 01:35:38 +00002270void vnc_display_init(DisplayState *ds)
bellard24236862006-04-30 21:28:36 +00002271{
bellard24236862006-04-30 21:28:36 +00002272 VncState *vs;
2273
2274 vs = qemu_mallocz(sizeof(VncState));
2275 if (!vs)
2276 exit(1);
2277
2278 ds->opaque = vs;
aliguoribcfad702008-08-21 20:08:55 +00002279 ds->idle = 1;
bellarda9ce8592007-02-05 20:20:30 +00002280 vnc_state = vs;
ths71cab5c2007-08-25 01:35:38 +00002281 vs->display = NULL;
ths70848512007-08-25 01:37:05 +00002282 vs->password = NULL;
bellard24236862006-04-30 21:28:36 +00002283
2284 vs->lsock = -1;
2285 vs->csock = -1;
bellard564c3372007-02-05 20:14:10 +00002286 vs->last_x = -1;
2287 vs->last_y = -1;
bellard24236862006-04-30 21:28:36 +00002288
2289 vs->ds = ds;
2290
aliguori9ca313a2008-08-23 23:27:37 +00002291 if (keyboard_layout)
2292 vs->kbd_layout = init_keyboard_layout(keyboard_layout);
2293 else
2294 vs->kbd_layout = init_keyboard_layout("en-us");
bellard24236862006-04-30 21:28:36 +00002295
bellard24236862006-04-30 21:28:36 +00002296 if (!vs->kbd_layout)
2297 exit(1);
2298
balroga0ecfb72008-01-13 23:51:53 +00002299 vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
2300
ths73fc9742006-12-22 02:09:07 +00002301 vs->ds->data = NULL;
2302 vs->ds->dpy_update = vnc_dpy_update;
2303 vs->ds->dpy_resize = vnc_dpy_resize;
balroga0ecfb72008-01-13 23:51:53 +00002304 vs->ds->dpy_refresh = NULL;
ths73fc9742006-12-22 02:09:07 +00002305
aliguori7eac3a82008-09-15 16:03:41 +00002306 vnc_colordepth(vs->ds, 32);
ths73fc9742006-12-22 02:09:07 +00002307 vnc_dpy_resize(vs->ds, 640, 400);
malc429a8ed2008-12-01 20:57:48 +00002308
2309 vs->as.freq = 44100;
2310 vs->as.nchannels = 2;
2311 vs->as.fmt = AUD_FMT_S16;
2312 vs->as.endianness = 0;
ths71cab5c2007-08-25 01:35:38 +00002313}
ths73fc9742006-12-22 02:09:07 +00002314
blueswir1eb38c522008-09-06 17:47:39 +00002315#ifdef CONFIG_VNC_TLS
ths6f430242007-08-25 01:39:57 +00002316static int vnc_set_x509_credential(VncState *vs,
2317 const char *certdir,
2318 const char *filename,
2319 char **cred,
2320 int ignoreMissing)
2321{
2322 struct stat sb;
2323
2324 if (*cred) {
2325 qemu_free(*cred);
2326 *cred = NULL;
2327 }
2328
2329 if (!(*cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2)))
2330 return -1;
2331
2332 strcpy(*cred, certdir);
2333 strcat(*cred, "/");
2334 strcat(*cred, filename);
2335
2336 VNC_DEBUG("Check %s\n", *cred);
2337 if (stat(*cred, &sb) < 0) {
2338 qemu_free(*cred);
2339 *cred = NULL;
2340 if (ignoreMissing && errno == ENOENT)
2341 return 0;
2342 return -1;
2343 }
2344
2345 return 0;
2346}
2347
2348static int vnc_set_x509_credential_dir(VncState *vs,
2349 const char *certdir)
2350{
2351 if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
2352 goto cleanup;
2353 if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0)
2354 goto cleanup;
2355 if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0)
2356 goto cleanup;
2357 if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0)
2358 goto cleanup;
2359
2360 return 0;
2361
2362 cleanup:
2363 qemu_free(vs->x509cacert);
2364 qemu_free(vs->x509cacrl);
2365 qemu_free(vs->x509cert);
2366 qemu_free(vs->x509key);
2367 vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL;
2368 return -1;
2369}
2370#endif /* CONFIG_VNC_TLS */
2371
ths71cab5c2007-08-25 01:35:38 +00002372void vnc_display_close(DisplayState *ds)
2373{
thse25a5822007-08-25 01:36:20 +00002374 VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
ths71cab5c2007-08-25 01:35:38 +00002375
2376 if (vs->display) {
2377 qemu_free(vs->display);
2378 vs->display = NULL;
2379 }
2380 if (vs->lsock != -1) {
2381 qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
2382 close(vs->lsock);
2383 vs->lsock = -1;
2384 }
2385 if (vs->csock != -1) {
2386 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
2387 closesocket(vs->csock);
2388 vs->csock = -1;
2389 buffer_reset(&vs->input);
2390 buffer_reset(&vs->output);
2391 vs->need_update = 0;
blueswir1eb38c522008-09-06 17:47:39 +00002392#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002393 if (vs->tls_session) {
2394 gnutls_deinit(vs->tls_session);
2395 vs->tls_session = NULL;
2396 }
2397 vs->wiremode = VNC_WIREMODE_CLEAR;
2398#endif /* CONFIG_VNC_TLS */
ths71cab5c2007-08-25 01:35:38 +00002399 }
ths70848512007-08-25 01:37:05 +00002400 vs->auth = VNC_AUTH_INVALID;
blueswir1eb38c522008-09-06 17:47:39 +00002401#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002402 vs->subauth = VNC_AUTH_INVALID;
ths469b15c2007-08-25 01:39:10 +00002403 vs->x509verify = 0;
ths8d5d2d42007-08-25 01:37:51 +00002404#endif
malc429a8ed2008-12-01 20:57:48 +00002405 audio_del(vs);
ths71cab5c2007-08-25 01:35:38 +00002406}
2407
ths70848512007-08-25 01:37:05 +00002408int vnc_display_password(DisplayState *ds, const char *password)
2409{
2410 VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
2411
2412 if (vs->password) {
2413 qemu_free(vs->password);
2414 vs->password = NULL;
2415 }
2416 if (password && password[0]) {
2417 if (!(vs->password = qemu_strdup(password)))
2418 return -1;
2419 }
2420
2421 return 0;
2422}
2423
2424int vnc_display_open(DisplayState *ds, const char *display)
ths71cab5c2007-08-25 01:35:38 +00002425{
thse25a5822007-08-25 01:36:20 +00002426 VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
ths70848512007-08-25 01:37:05 +00002427 const char *options;
2428 int password = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002429 int reverse = 0;
aliguori9712eca2008-11-11 20:51:59 +00002430 int to_port = 0;
blueswir1eb38c522008-09-06 17:47:39 +00002431#ifdef CONFIG_VNC_TLS
ths3a702692007-08-25 01:38:36 +00002432 int tls = 0, x509 = 0;
ths8d5d2d42007-08-25 01:37:51 +00002433#endif
ths71cab5c2007-08-25 01:35:38 +00002434
2435 vnc_display_close(ds);
ths70848512007-08-25 01:37:05 +00002436 if (strcmp(display, "none") == 0)
ths71cab5c2007-08-25 01:35:38 +00002437 return 0;
2438
ths70848512007-08-25 01:37:05 +00002439 if (!(vs->display = strdup(display)))
ths71cab5c2007-08-25 01:35:38 +00002440 return -1;
ths70848512007-08-25 01:37:05 +00002441
2442 options = display;
2443 while ((options = strchr(options, ','))) {
2444 options++;
ths469b15c2007-08-25 01:39:10 +00002445 if (strncmp(options, "password", 8) == 0) {
ths70848512007-08-25 01:37:05 +00002446 password = 1; /* Require password auth */
balrog3aa3eea2008-02-03 02:54:04 +00002447 } else if (strncmp(options, "reverse", 7) == 0) {
2448 reverse = 1;
aliguori9712eca2008-11-11 20:51:59 +00002449 } else if (strncmp(options, "to=", 3) == 0) {
2450 to_port = atoi(options+3) + 5900;
blueswir1eb38c522008-09-06 17:47:39 +00002451#ifdef CONFIG_VNC_TLS
ths469b15c2007-08-25 01:39:10 +00002452 } else if (strncmp(options, "tls", 3) == 0) {
ths8d5d2d42007-08-25 01:37:51 +00002453 tls = 1; /* Require TLS */
ths469b15c2007-08-25 01:39:10 +00002454 } else if (strncmp(options, "x509", 4) == 0) {
ths6f430242007-08-25 01:39:57 +00002455 char *start, *end;
ths3a702692007-08-25 01:38:36 +00002456 x509 = 1; /* Require x509 certificates */
ths6f430242007-08-25 01:39:57 +00002457 if (strncmp(options, "x509verify", 10) == 0)
2458 vs->x509verify = 1; /* ...and verify client certs */
2459
2460 /* Now check for 'x509=/some/path' postfix
2461 * and use that to setup x509 certificate/key paths */
2462 start = strchr(options, '=');
2463 end = strchr(options, ',');
2464 if (start && (!end || (start < end))) {
2465 int len = end ? end-(start+1) : strlen(start+1);
balrogbe351262008-11-12 16:50:36 +00002466 char *path = qemu_strndup(start + 1, len);
blueswir1be15b142008-10-25 11:21:28 +00002467
ths6f430242007-08-25 01:39:57 +00002468 VNC_DEBUG("Trying certificate path '%s'\n", path);
2469 if (vnc_set_x509_credential_dir(vs, path) < 0) {
2470 fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
2471 qemu_free(path);
2472 qemu_free(vs->display);
2473 vs->display = NULL;
2474 return -1;
2475 }
2476 qemu_free(path);
2477 } else {
2478 fprintf(stderr, "No certificate path provided\n");
2479 qemu_free(vs->display);
2480 vs->display = NULL;
2481 return -1;
2482 }
ths8d5d2d42007-08-25 01:37:51 +00002483#endif
ths469b15c2007-08-25 01:39:10 +00002484 }
ths70848512007-08-25 01:37:05 +00002485 }
2486
2487 if (password) {
blueswir1eb38c522008-09-06 17:47:39 +00002488#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002489 if (tls) {
ths8d5d2d42007-08-25 01:37:51 +00002490 vs->auth = VNC_AUTH_VENCRYPT;
ths3a702692007-08-25 01:38:36 +00002491 if (x509) {
2492 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
2493 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
2494 } else {
2495 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
2496 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
2497 }
ths8d5d2d42007-08-25 01:37:51 +00002498 } else {
2499#endif
2500 VNC_DEBUG("Initializing VNC server with password auth\n");
2501 vs->auth = VNC_AUTH_VNC;
blueswir1eb38c522008-09-06 17:47:39 +00002502#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002503 vs->subauth = VNC_AUTH_INVALID;
2504 }
2505#endif
ths70848512007-08-25 01:37:05 +00002506 } else {
blueswir1eb38c522008-09-06 17:47:39 +00002507#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002508 if (tls) {
ths8d5d2d42007-08-25 01:37:51 +00002509 vs->auth = VNC_AUTH_VENCRYPT;
ths3a702692007-08-25 01:38:36 +00002510 if (x509) {
2511 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
2512 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
2513 } else {
2514 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
2515 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
2516 }
ths8d5d2d42007-08-25 01:37:51 +00002517 } else {
2518#endif
2519 VNC_DEBUG("Initializing VNC server with no auth\n");
2520 vs->auth = VNC_AUTH_NONE;
blueswir1eb38c522008-09-06 17:47:39 +00002521#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002522 vs->subauth = VNC_AUTH_INVALID;
2523 }
2524#endif
ths70848512007-08-25 01:37:05 +00002525 }
bellard24236862006-04-30 21:28:36 +00002526
balrog3aa3eea2008-02-03 02:54:04 +00002527 if (reverse) {
aliguori9712eca2008-11-11 20:51:59 +00002528 /* connect to viewer */
2529 if (strncmp(display, "unix:", 5) == 0)
2530 vs->lsock = unix_connect(display+5);
2531 else
2532 vs->lsock = inet_connect(display, SOCK_STREAM);
2533 if (-1 == vs->lsock) {
balrog3aa3eea2008-02-03 02:54:04 +00002534 free(vs->display);
2535 vs->display = NULL;
2536 return -1;
2537 } else {
2538 vs->csock = vs->lsock;
2539 vs->lsock = -1;
2540 vnc_connect(vs);
balrog3aa3eea2008-02-03 02:54:04 +00002541 }
aliguori9712eca2008-11-11 20:51:59 +00002542 return 0;
balrog3aa3eea2008-02-03 02:54:04 +00002543
aliguori9712eca2008-11-11 20:51:59 +00002544 } else {
2545 /* listen for connects */
2546 char *dpy;
2547 dpy = qemu_malloc(256);
2548 if (strncmp(display, "unix:", 5) == 0) {
2549 strcpy(dpy, "unix:");
aliguori4a55bfd2008-12-02 20:02:14 +00002550 vs->lsock = unix_listen(display+5, dpy+5, 256-5);
aliguori9712eca2008-11-11 20:51:59 +00002551 } else {
2552 vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
2553 }
2554 if (-1 == vs->lsock) {
2555 free(dpy);
balrogd0513622008-12-01 01:48:36 +00002556 return -1;
aliguori9712eca2008-11-11 20:51:59 +00002557 } else {
2558 free(vs->display);
2559 vs->display = dpy;
2560 }
bellard24236862006-04-30 21:28:36 +00002561 }
2562
ths71cab5c2007-08-25 01:35:38 +00002563 return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00002564}