blob: bdfc79b84dcecef5e63c7d43eb49cd47b02bea1f [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"
aliguori059cef42009-02-02 15:58:54 +000032#include <zlib.h>
bellard24236862006-04-30 21:28:36 +000033
34#define VNC_REFRESH_INTERVAL (1000 / 30)
35
aliguorie06679f2009-02-02 15:58:25 +000036#include "vnc.h"
bellard24236862006-04-30 21:28:36 +000037#include "vnc_keysym.h"
38#include "keymaps.c"
ths70848512007-08-25 01:37:05 +000039#include "d3des.h"
40
blueswir1eb38c522008-09-06 17:47:39 +000041#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +000042#include <gnutls/gnutls.h>
43#include <gnutls/x509.h>
44#endif /* CONFIG_VNC_TLS */
ths70848512007-08-25 01:37:05 +000045
ths8d5d2d42007-08-25 01:37:51 +000046// #define _VNC_DEBUG 1
47
blueswir1eb38c522008-09-06 17:47:39 +000048#ifdef _VNC_DEBUG
ths70848512007-08-25 01:37:05 +000049#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
ths8d5d2d42007-08-25 01:37:51 +000050
aliguori26f8b9c2009-02-02 15:58:38 +000051#if defined(CONFIG_VNC_TLS) && _VNC_DEBUG >= 2
ths8d5d2d42007-08-25 01:37:51 +000052/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
53static void vnc_debug_gnutls_log(int level, const char* str) {
54 VNC_DEBUG("%d %s", level, str);
55}
56#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
ths70848512007-08-25 01:37:05 +000057#else
58#define VNC_DEBUG(fmt, ...) do { } while (0)
59#endif
bellard24236862006-04-30 21:28:36 +000060
aliguori90a1e3c2009-01-26 15:37:30 +000061#define count_bits(c, v) { \
62 for (c = 0; v; v >>= 1) \
63 { \
64 c += v & 1; \
65 } \
66}
ths8d5d2d42007-08-25 01:37:51 +000067
bellard24236862006-04-30 21:28:36 +000068typedef struct Buffer
69{
70 size_t capacity;
71 size_t offset;
ths60fe76f2007-12-16 03:02:09 +000072 uint8_t *buffer;
bellard24236862006-04-30 21:28:36 +000073} Buffer;
74
75typedef struct VncState VncState;
76
ths60fe76f2007-12-16 03:02:09 +000077typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
bellard24236862006-04-30 21:28:36 +000078
bellard35127792006-05-14 18:11:49 +000079typedef void VncWritePixels(VncState *vs, void *data, int size);
80
81typedef void VncSendHextileTile(VncState *vs,
82 int x, int y, int w, int h,
aliguori7eac3a82008-09-15 16:03:41 +000083 void *last_bg,
84 void *last_fg,
bellard35127792006-05-14 18:11:49 +000085 int *has_bg, int *has_fg);
86
bellard99589bd2006-06-13 16:35:24 +000087#define VNC_MAX_WIDTH 2048
88#define VNC_MAX_HEIGHT 2048
89#define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
90
ths70848512007-08-25 01:37:05 +000091#define VNC_AUTH_CHALLENGE_SIZE 16
92
bellard24236862006-04-30 21:28:36 +000093struct VncState
94{
95 QEMUTimer *timer;
96 int lsock;
97 int csock;
98 DisplayState *ds;
99 int need_update;
bellard99589bd2006-06-13 16:35:24 +0000100 uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
bellard24236862006-04-30 21:28:36 +0000101 char *old_data;
aliguori29fa4ed2009-02-02 15:58:29 +0000102 uint32_t features;
bellard564c3372007-02-05 20:14:10 +0000103 int absolute;
104 int last_x;
105 int last_y;
106
aliguorifb437312009-02-02 15:58:43 +0000107 uint32_t vnc_encoding;
108 uint8_t tight_quality;
109 uint8_t tight_compression;
110
ths70848512007-08-25 01:37:05 +0000111 int major;
112 int minor;
113
ths71cab5c2007-08-25 01:35:38 +0000114 char *display;
ths70848512007-08-25 01:37:05 +0000115 char *password;
116 int auth;
blueswir1eb38c522008-09-06 17:47:39 +0000117#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000118 int subauth;
ths469b15c2007-08-25 01:39:10 +0000119 int x509verify;
ths6f430242007-08-25 01:39:57 +0000120
121 char *x509cacert;
122 char *x509cacrl;
123 char *x509cert;
124 char *x509key;
ths8d5d2d42007-08-25 01:37:51 +0000125#endif
ths70848512007-08-25 01:37:05 +0000126 char challenge[VNC_AUTH_CHALLENGE_SIZE];
bellarda9ce8592007-02-05 20:20:30 +0000127
blueswir1eb38c522008-09-06 17:47:39 +0000128#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000129 int wiremode;
130 gnutls_session_t tls_session;
131#endif
132
bellard24236862006-04-30 21:28:36 +0000133 Buffer output;
134 Buffer input;
135 kbd_layout_t *kbd_layout;
bellard35127792006-05-14 18:11:49 +0000136 /* current output mode information */
137 VncWritePixels *write_pixels;
138 VncSendHextileTile *send_hextile_tile;
aliguori6cec5482009-01-15 22:17:38 +0000139 DisplaySurface clientds, serverds;
bellard24236862006-04-30 21:28:36 +0000140
malc429a8ed2008-12-01 20:57:48 +0000141 CaptureVoiceOut *audio_cap;
malc1ea879e2008-12-03 22:48:44 +0000142 struct audsettings as;
malc429a8ed2008-12-01 20:57:48 +0000143
bellard24236862006-04-30 21:28:36 +0000144 VncReadEvent *read_handler;
145 size_t read_handler_expect;
bellard64f5a132006-08-24 20:36:44 +0000146 /* input */
147 uint8_t modifiers_state[256];
aliguori059cef42009-02-02 15:58:54 +0000148
149 Buffer zlib;
150 Buffer zlib_tmp;
151 z_stream zlib_stream[4];
bellard24236862006-04-30 21:28:36 +0000152};
153
bellarda9ce8592007-02-05 20:20:30 +0000154static VncState *vnc_state; /* needed for info vnc */
aliguori7d957bd2009-01-15 22:14:11 +0000155static DisplayChangeListener *dcl;
bellarda9ce8592007-02-05 20:20:30 +0000156
157void do_info_vnc(void)
158{
aurel3213412c92008-12-13 18:57:12 +0000159 if (vnc_state == NULL || vnc_state->display == NULL)
bellarda9ce8592007-02-05 20:20:30 +0000160 term_printf("VNC server disabled\n");
161 else {
162 term_printf("VNC server active on: ");
163 term_print_filename(vnc_state->display);
164 term_printf("\n");
165
166 if (vnc_state->csock == -1)
167 term_printf("No client connected\n");
168 else
169 term_printf("Client connected\n");
170 }
171}
172
aliguori29fa4ed2009-02-02 15:58:29 +0000173static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
174 return (vs->features & (1 << feature));
175}
176
bellard24236862006-04-30 21:28:36 +0000177/* TODO
178 1) Get the queue working for IO.
179 2) there is some weirdness when using the -S option (the screen is grey
180 and not totally invalidated
181 3) resolutions > 1024
182*/
183
184static void vnc_write(VncState *vs, const void *data, size_t len);
185static void vnc_write_u32(VncState *vs, uint32_t value);
186static void vnc_write_s32(VncState *vs, int32_t value);
187static void vnc_write_u16(VncState *vs, uint16_t value);
188static void vnc_write_u8(VncState *vs, uint8_t value);
189static void vnc_flush(VncState *vs);
190static void vnc_update_client(void *opaque);
191static void vnc_client_read(void *opaque);
192
aliguori7d957bd2009-01-15 22:14:11 +0000193static void vnc_colordepth(DisplayState *ds);
aliguori7eac3a82008-09-15 16:03:41 +0000194
bellard99589bd2006-06-13 16:35:24 +0000195static inline void vnc_set_bit(uint32_t *d, int k)
196{
197 d[k >> 5] |= 1 << (k & 0x1f);
198}
199
200static inline void vnc_clear_bit(uint32_t *d, int k)
201{
202 d[k >> 5] &= ~(1 << (k & 0x1f));
203}
204
205static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
206{
207 int j;
208
209 j = 0;
210 while (n >= 32) {
211 d[j++] = -1;
212 n -= 32;
213 }
ths5fafdf22007-09-16 21:08:06 +0000214 if (n > 0)
bellard99589bd2006-06-13 16:35:24 +0000215 d[j++] = (1 << n) - 1;
216 while (j < nb_words)
217 d[j++] = 0;
218}
219
220static inline int vnc_get_bit(const uint32_t *d, int k)
221{
222 return (d[k >> 5] >> (k & 0x1f)) & 1;
223}
224
ths5fafdf22007-09-16 21:08:06 +0000225static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
bellard99589bd2006-06-13 16:35:24 +0000226 int nb_words)
227{
228 int i;
229 for(i = 0; i < nb_words; i++) {
230 if ((d1[i] & d2[i]) != 0)
231 return 1;
232 }
233 return 0;
234}
235
bellard24236862006-04-30 21:28:36 +0000236static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
237{
238 VncState *vs = ds->opaque;
239 int i;
240
241 h += y;
242
balrog0486e8a2007-12-11 22:31:32 +0000243 /* round x down to ensure the loop only spans one 16-pixel block per,
244 iteration. otherwise, if (x % 16) != 0, the last iteration may span
245 two 16-pixel blocks but we only mark the first as dirty
246 */
247 w += (x % 16);
248 x -= (x % 16);
249
aliguori6cec5482009-01-15 22:17:38 +0000250 x = MIN(x, vs->serverds.width);
251 y = MIN(y, vs->serverds.height);
252 w = MIN(x + w, vs->serverds.width) - x;
253 h = MIN(h, vs->serverds.height);
balrog788abf82008-05-20 00:07:58 +0000254
bellard24236862006-04-30 21:28:36 +0000255 for (; y < h; y++)
256 for (i = 0; i < w; i += 16)
bellard99589bd2006-06-13 16:35:24 +0000257 vnc_set_bit(vs->dirty_row[y], (x + i) / 16);
bellard24236862006-04-30 21:28:36 +0000258}
259
260static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
261 int32_t encoding)
262{
263 vnc_write_u16(vs, x);
264 vnc_write_u16(vs, y);
265 vnc_write_u16(vs, w);
266 vnc_write_u16(vs, h);
267
268 vnc_write_s32(vs, encoding);
269}
270
aliguori89064282009-02-02 15:58:47 +0000271static void buffer_reserve(Buffer *buffer, size_t len)
272{
273 if ((buffer->capacity - buffer->offset) < len) {
274 buffer->capacity += (len + 1024);
275 buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
276 if (buffer->buffer == NULL) {
277 fprintf(stderr, "vnc: out of memory\n");
278 exit(1);
279 }
280 }
281}
282
283static int buffer_empty(Buffer *buffer)
284{
285 return buffer->offset == 0;
286}
287
288static uint8_t *buffer_end(Buffer *buffer)
289{
290 return buffer->buffer + buffer->offset;
291}
292
293static void buffer_reset(Buffer *buffer)
294{
295 buffer->offset = 0;
296}
297
298static void buffer_append(Buffer *buffer, const void *data, size_t len)
299{
300 memcpy(buffer->buffer + buffer->offset, data, len);
301 buffer->offset += len;
302}
303
aliguori7d957bd2009-01-15 22:14:11 +0000304static void vnc_dpy_resize(DisplayState *ds)
bellard24236862006-04-30 21:28:36 +0000305{
ths73e14b62006-12-14 13:36:01 +0000306 int size_changed;
bellard24236862006-04-30 21:28:36 +0000307 VncState *vs = ds->opaque;
308
aliguori7d957bd2009-01-15 22:14:11 +0000309 vs->old_data = qemu_realloc(vs->old_data, ds_get_linesize(ds) * ds_get_height(ds));
bellard24236862006-04-30 21:28:36 +0000310
aliguori7d957bd2009-01-15 22:14:11 +0000311 if (vs->old_data == NULL) {
bellard24236862006-04-30 21:28:36 +0000312 fprintf(stderr, "vnc: memory allocation failed\n");
313 exit(1);
314 }
315
aliguori6cec5482009-01-15 22:17:38 +0000316 if (ds_get_bytes_per_pixel(ds) != vs->serverds.pf.bytes_per_pixel)
balroga528b802007-10-30 22:38:53 +0000317 console_color_init(ds);
aliguori7d957bd2009-01-15 22:14:11 +0000318 vnc_colordepth(ds);
aliguori6cec5482009-01-15 22:17:38 +0000319 size_changed = ds_get_width(ds) != vs->serverds.width ||
320 ds_get_height(ds) != vs->serverds.height;
321 vs->serverds = *(ds->surface);
balrogb94eb432008-06-02 01:40:29 +0000322 if (size_changed) {
aliguori29fa4ed2009-02-02 15:58:29 +0000323 if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
balrogb94eb432008-06-02 01:40:29 +0000324 vnc_write_u8(vs, 0); /* msg id */
325 vnc_write_u8(vs, 0);
326 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000327 vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
328 VNC_ENCODING_DESKTOPRESIZE);
balrogb94eb432008-06-02 01:40:29 +0000329 vnc_flush(vs);
330 }
bellard24236862006-04-30 21:28:36 +0000331 }
balrog8bba5c82008-05-25 00:14:34 +0000332
333 memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
aliguori0e1f5a02008-11-24 19:29:13 +0000334 memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
bellard24236862006-04-30 21:28:36 +0000335}
336
bellard35127792006-05-14 18:11:49 +0000337/* fastest code */
338static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
339{
340 vnc_write(vs, pixels, size);
341}
342
343/* slowest but generic code. */
344static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
345{
aliguori7eac3a82008-09-15 16:03:41 +0000346 uint8_t r, g, b;
bellard35127792006-05-14 18:11:49 +0000347
aliguori90a1e3c2009-01-26 15:37:30 +0000348 r = ((((v & vs->serverds.pf.rmask) >> vs->serverds.pf.rshift) << vs->clientds.pf.rbits) >>
349 vs->serverds.pf.rbits);
350 g = ((((v & vs->serverds.pf.gmask) >> vs->serverds.pf.gshift) << vs->clientds.pf.gbits) >>
351 vs->serverds.pf.gbits);
352 b = ((((v & vs->serverds.pf.bmask) >> vs->serverds.pf.bshift) << vs->clientds.pf.bbits) >>
353 vs->serverds.pf.bbits);
aliguori6cec5482009-01-15 22:17:38 +0000354 v = (r << vs->clientds.pf.rshift) |
355 (g << vs->clientds.pf.gshift) |
356 (b << vs->clientds.pf.bshift);
357 switch(vs->clientds.pf.bytes_per_pixel) {
bellard35127792006-05-14 18:11:49 +0000358 case 1:
359 buf[0] = v;
360 break;
361 case 2:
aliguori6cec5482009-01-15 22:17:38 +0000362 if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
bellard35127792006-05-14 18:11:49 +0000363 buf[0] = v >> 8;
364 buf[1] = v;
365 } else {
366 buf[1] = v >> 8;
367 buf[0] = v;
368 }
369 break;
370 default:
371 case 4:
aliguori6cec5482009-01-15 22:17:38 +0000372 if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
bellard35127792006-05-14 18:11:49 +0000373 buf[0] = v >> 24;
374 buf[1] = v >> 16;
375 buf[2] = v >> 8;
376 buf[3] = v;
377 } else {
378 buf[3] = v >> 24;
379 buf[2] = v >> 16;
380 buf[1] = v >> 8;
381 buf[0] = v;
382 }
383 break;
384 }
385}
386
387static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
388{
bellard35127792006-05-14 18:11:49 +0000389 uint8_t buf[4];
bellard35127792006-05-14 18:11:49 +0000390
aliguori6cec5482009-01-15 22:17:38 +0000391 if (vs->serverds.pf.bytes_per_pixel == 4) {
aliguori7eac3a82008-09-15 16:03:41 +0000392 uint32_t *pixels = pixels1;
393 int n, i;
394 n = size >> 2;
395 for(i = 0; i < n; i++) {
396 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000397 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000398 }
aliguori6cec5482009-01-15 22:17:38 +0000399 } else if (vs->serverds.pf.bytes_per_pixel == 2) {
aliguori7eac3a82008-09-15 16:03:41 +0000400 uint16_t *pixels = pixels1;
401 int n, i;
402 n = size >> 1;
403 for(i = 0; i < n; i++) {
404 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000405 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000406 }
aliguori6cec5482009-01-15 22:17:38 +0000407 } else if (vs->serverds.pf.bytes_per_pixel == 1) {
aliguori7eac3a82008-09-15 16:03:41 +0000408 uint8_t *pixels = pixels1;
409 int n, i;
410 n = size;
411 for(i = 0; i < n; i++) {
412 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000413 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000414 }
415 } else {
416 fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
bellard35127792006-05-14 18:11:49 +0000417 }
418}
419
bellard24236862006-04-30 21:28:36 +0000420static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
421{
422 int i;
ths60fe76f2007-12-16 03:02:09 +0000423 uint8_t *row;
bellard24236862006-04-30 21:28:36 +0000424
aliguori6cec5482009-01-15 22:17:38 +0000425 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 +0000426 for (i = 0; i < h; i++) {
aliguori6cec5482009-01-15 22:17:38 +0000427 vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
aliguori0e1f5a02008-11-24 19:29:13 +0000428 row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +0000429 }
430}
431
432static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
433{
434 ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
435 ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
436}
437
438#define BPP 8
439#include "vnchextile.h"
440#undef BPP
441
442#define BPP 16
443#include "vnchextile.h"
444#undef BPP
445
446#define BPP 32
447#include "vnchextile.h"
448#undef BPP
449
bellard35127792006-05-14 18:11:49 +0000450#define GENERIC
aliguori7eac3a82008-09-15 16:03:41 +0000451#define BPP 8
452#include "vnchextile.h"
453#undef BPP
454#undef GENERIC
455
456#define GENERIC
457#define BPP 16
458#include "vnchextile.h"
459#undef BPP
460#undef GENERIC
461
462#define GENERIC
bellard35127792006-05-14 18:11:49 +0000463#define BPP 32
464#include "vnchextile.h"
465#undef BPP
466#undef GENERIC
467
bellard24236862006-04-30 21:28:36 +0000468static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
469{
470 int i, j;
471 int has_fg, has_bg;
aliguori7eac3a82008-09-15 16:03:41 +0000472 uint8_t *last_fg, *last_bg;
bellard24236862006-04-30 21:28:36 +0000473
aliguori1eec6142009-02-05 22:06:18 +0000474 last_fg = (uint8_t *) qemu_malloc(vs->serverds.pf.bytes_per_pixel);
475 last_bg = (uint8_t *) qemu_malloc(vs->serverds.pf.bytes_per_pixel);
bellard24236862006-04-30 21:28:36 +0000476 has_fg = has_bg = 0;
477 for (j = y; j < (y + h); j += 16) {
478 for (i = x; i < (x + w); i += 16) {
ths5fafdf22007-09-16 21:08:06 +0000479 vs->send_hextile_tile(vs, i, j,
bellard35127792006-05-14 18:11:49 +0000480 MIN(16, x + w - i), MIN(16, y + h - j),
aliguori7eac3a82008-09-15 16:03:41 +0000481 last_bg, last_fg, &has_bg, &has_fg);
bellard24236862006-04-30 21:28:36 +0000482 }
483 }
aliguori7eac3a82008-09-15 16:03:41 +0000484 free(last_fg);
485 free(last_bg);
486
bellard24236862006-04-30 21:28:36 +0000487}
488
aliguori059cef42009-02-02 15:58:54 +0000489static void vnc_zlib_init(VncState *vs)
490{
491 int i;
492 for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++)
493 vs->zlib_stream[i].opaque = NULL;
494}
495
496static void vnc_zlib_start(VncState *vs)
497{
498 buffer_reset(&vs->zlib);
499
500 // make the output buffer be the zlib buffer, so we can compress it later
501 vs->zlib_tmp = vs->output;
502 vs->output = vs->zlib;
503}
504
505static int vnc_zlib_stop(VncState *vs, int stream_id)
506{
507 z_streamp zstream = &vs->zlib_stream[stream_id];
508 int previous_out;
509
510 // switch back to normal output/zlib buffers
511 vs->zlib = vs->output;
512 vs->output = vs->zlib_tmp;
513
514 // compress the zlib buffer
515
516 // initialize the stream
517 // XXX need one stream per session
518 if (zstream->opaque != vs) {
519 int err;
520
521 VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
522 VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
523 zstream->zalloc = Z_NULL;
524 zstream->zfree = Z_NULL;
525
526 err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
527 MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
528
529 if (err != Z_OK) {
530 fprintf(stderr, "VNC: error initializing zlib\n");
531 return -1;
532 }
533
534 zstream->opaque = vs;
535 }
536
537 // XXX what to do if tight_compression changed in between?
538
539 // reserve memory in output buffer
540 buffer_reserve(&vs->output, vs->zlib.offset + 64);
541
542 // set pointers
543 zstream->next_in = vs->zlib.buffer;
544 zstream->avail_in = vs->zlib.offset;
545 zstream->next_out = vs->output.buffer + vs->output.offset;
546 zstream->avail_out = vs->output.capacity - vs->output.offset;
547 zstream->data_type = Z_BINARY;
548 previous_out = zstream->total_out;
549
550 // start encoding
551 if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
552 fprintf(stderr, "VNC: error during zlib compression\n");
553 return -1;
554 }
555
556 vs->output.offset = vs->output.capacity - zstream->avail_out;
557 return zstream->total_out - previous_out;
558}
559
560static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h)
561{
562 int old_offset, new_offset, bytes_written;
563
564 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
565
566 // remember where we put in the follow-up size
567 old_offset = vs->output.offset;
568 vnc_write_s32(vs, 0);
569
570 // compress the stream
571 vnc_zlib_start(vs);
572 send_framebuffer_update_raw(vs, x, y, w, h);
573 bytes_written = vnc_zlib_stop(vs, 0);
574
575 if (bytes_written == -1)
576 return;
577
578 // hack in the size
579 new_offset = vs->output.offset;
580 vs->output.offset = old_offset;
581 vnc_write_u32(vs, bytes_written);
582 vs->output.offset = new_offset;
583}
584
bellard24236862006-04-30 21:28:36 +0000585static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
586{
aliguorifb437312009-02-02 15:58:43 +0000587 switch(vs->vnc_encoding) {
aliguori059cef42009-02-02 15:58:54 +0000588 case VNC_ENCODING_ZLIB:
589 send_framebuffer_update_zlib(vs, x, y, w, h);
590 break;
aliguorifb437312009-02-02 15:58:43 +0000591 case VNC_ENCODING_HEXTILE:
aliguorid2a01022009-02-02 15:58:51 +0000592 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
bellard24236862006-04-30 21:28:36 +0000593 send_framebuffer_update_hextile(vs, x, y, w, h);
aliguorifb437312009-02-02 15:58:43 +0000594 break;
595 default:
aliguorid2a01022009-02-02 15:58:51 +0000596 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
bellard24236862006-04-30 21:28:36 +0000597 send_framebuffer_update_raw(vs, x, y, w, h);
aliguorifb437312009-02-02 15:58:43 +0000598 break;
599 }
bellard24236862006-04-30 21:28:36 +0000600}
601
602static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
603{
bellard24236862006-04-30 21:28:36 +0000604 VncState *vs = ds->opaque;
605
606 vnc_update_client(vs);
607
bellard24236862006-04-30 21:28:36 +0000608 vnc_write_u8(vs, 0); /* msg id */
609 vnc_write_u8(vs, 0);
610 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000611 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
bellard24236862006-04-30 21:28:36 +0000612 vnc_write_u16(vs, src_x);
613 vnc_write_u16(vs, src_y);
614 vnc_flush(vs);
615}
616
617static int find_dirty_height(VncState *vs, int y, int last_x, int x)
618{
619 int h;
620
aliguori6cec5482009-01-15 22:17:38 +0000621 for (h = 1; h < (vs->serverds.height - y); h++) {
bellard24236862006-04-30 21:28:36 +0000622 int tmp_x;
bellard99589bd2006-06-13 16:35:24 +0000623 if (!vnc_get_bit(vs->dirty_row[y + h], last_x))
bellard24236862006-04-30 21:28:36 +0000624 break;
625 for (tmp_x = last_x; tmp_x < x; tmp_x++)
bellard99589bd2006-06-13 16:35:24 +0000626 vnc_clear_bit(vs->dirty_row[y + h], tmp_x);
bellard24236862006-04-30 21:28:36 +0000627 }
628
629 return h;
630}
631
632static void vnc_update_client(void *opaque)
633{
634 VncState *vs = opaque;
635
636 if (vs->need_update && vs->csock != -1) {
637 int y;
ths60fe76f2007-12-16 03:02:09 +0000638 uint8_t *row;
bellard24236862006-04-30 21:28:36 +0000639 char *old_row;
bellard99589bd2006-06-13 16:35:24 +0000640 uint32_t width_mask[VNC_DIRTY_WORDS];
bellard24236862006-04-30 21:28:36 +0000641 int n_rectangles;
642 int saved_offset;
643 int has_dirty = 0;
644
balroga0ecfb72008-01-13 23:51:53 +0000645 vga_hw_update();
646
aliguori6cec5482009-01-15 22:17:38 +0000647 vnc_set_bits(width_mask, (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
bellard24236862006-04-30 21:28:36 +0000648
649 /* Walk through the dirty map and eliminate tiles that
650 really aren't dirty */
aliguori0e1f5a02008-11-24 19:29:13 +0000651 row = ds_get_data(vs->ds);
bellard24236862006-04-30 21:28:36 +0000652 old_row = vs->old_data;
653
aliguori6cec5482009-01-15 22:17:38 +0000654 for (y = 0; y < ds_get_height(vs->ds); y++) {
bellard99589bd2006-06-13 16:35:24 +0000655 if (vnc_and_bits(vs->dirty_row[y], width_mask, VNC_DIRTY_WORDS)) {
bellard24236862006-04-30 21:28:36 +0000656 int x;
ths60fe76f2007-12-16 03:02:09 +0000657 uint8_t *ptr;
658 char *old_ptr;
bellard24236862006-04-30 21:28:36 +0000659
660 ptr = row;
ths60fe76f2007-12-16 03:02:09 +0000661 old_ptr = (char*)old_row;
bellard24236862006-04-30 21:28:36 +0000662
aliguori0e1f5a02008-11-24 19:29:13 +0000663 for (x = 0; x < ds_get_width(vs->ds); x += 16) {
aliguori6cec5482009-01-15 22:17:38 +0000664 if (memcmp(old_ptr, ptr, 16 * ds_get_bytes_per_pixel(vs->ds)) == 0) {
bellard99589bd2006-06-13 16:35:24 +0000665 vnc_clear_bit(vs->dirty_row[y], (x / 16));
bellard24236862006-04-30 21:28:36 +0000666 } else {
667 has_dirty = 1;
aliguori6cec5482009-01-15 22:17:38 +0000668 memcpy(old_ptr, ptr, 16 * ds_get_bytes_per_pixel(vs->ds));
bellard24236862006-04-30 21:28:36 +0000669 }
670
aliguori6cec5482009-01-15 22:17:38 +0000671 ptr += 16 * ds_get_bytes_per_pixel(vs->ds);
672 old_ptr += 16 * ds_get_bytes_per_pixel(vs->ds);
bellard24236862006-04-30 21:28:36 +0000673 }
674 }
675
aliguori0e1f5a02008-11-24 19:29:13 +0000676 row += ds_get_linesize(vs->ds);
677 old_row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +0000678 }
679
malc429a8ed2008-12-01 20:57:48 +0000680 if (!has_dirty && !vs->audio_cap) {
bellard24236862006-04-30 21:28:36 +0000681 qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
682 return;
683 }
684
685 /* Count rectangles */
686 n_rectangles = 0;
687 vnc_write_u8(vs, 0); /* msg id */
688 vnc_write_u8(vs, 0);
689 saved_offset = vs->output.offset;
690 vnc_write_u16(vs, 0);
691
aliguori6cec5482009-01-15 22:17:38 +0000692 for (y = 0; y < vs->serverds.height; y++) {
bellard24236862006-04-30 21:28:36 +0000693 int x;
694 int last_x = -1;
aliguori6cec5482009-01-15 22:17:38 +0000695 for (x = 0; x < vs->serverds.width / 16; x++) {
bellard99589bd2006-06-13 16:35:24 +0000696 if (vnc_get_bit(vs->dirty_row[y], x)) {
bellard24236862006-04-30 21:28:36 +0000697 if (last_x == -1) {
698 last_x = x;
699 }
bellard99589bd2006-06-13 16:35:24 +0000700 vnc_clear_bit(vs->dirty_row[y], x);
bellard24236862006-04-30 21:28:36 +0000701 } else {
702 if (last_x != -1) {
703 int h = find_dirty_height(vs, y, last_x, x);
704 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
705 n_rectangles++;
706 }
707 last_x = -1;
708 }
709 }
710 if (last_x != -1) {
711 int h = find_dirty_height(vs, y, last_x, x);
712 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
713 n_rectangles++;
714 }
715 }
716 vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
717 vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
718 vnc_flush(vs);
719
720 }
bellard24236862006-04-30 21:28:36 +0000721
balroga0ecfb72008-01-13 23:51:53 +0000722 if (vs->csock != -1) {
723 qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
bellard24236862006-04-30 21:28:36 +0000724 }
bellard24236862006-04-30 21:28:36 +0000725
bellard24236862006-04-30 21:28:36 +0000726}
727
728static int vnc_listen_poll(void *opaque)
729{
730 VncState *vs = opaque;
731 if (vs->csock == -1)
732 return 1;
733 return 0;
734}
735
malc429a8ed2008-12-01 20:57:48 +0000736/* audio */
737static void audio_capture_notify(void *opaque, audcnotification_e cmd)
738{
739 VncState *vs = opaque;
740
741 switch (cmd) {
742 case AUD_CNOTIFY_DISABLE:
743 vnc_write_u8(vs, 255);
744 vnc_write_u8(vs, 1);
745 vnc_write_u16(vs, 0);
746 vnc_flush(vs);
747 break;
748
749 case AUD_CNOTIFY_ENABLE:
750 vnc_write_u8(vs, 255);
751 vnc_write_u8(vs, 1);
752 vnc_write_u16(vs, 1);
753 vnc_flush(vs);
754 break;
755 }
756}
757
758static void audio_capture_destroy(void *opaque)
759{
760}
761
762static void audio_capture(void *opaque, void *buf, int size)
763{
764 VncState *vs = opaque;
765
766 vnc_write_u8(vs, 255);
767 vnc_write_u8(vs, 1);
768 vnc_write_u16(vs, 2);
769 vnc_write_u32(vs, size);
770 vnc_write(vs, buf, size);
771 vnc_flush(vs);
772}
773
774static void audio_add(VncState *vs)
775{
776 struct audio_capture_ops ops;
777
778 if (vs->audio_cap) {
779 term_printf ("audio already running\n");
780 return;
781 }
782
783 ops.notify = audio_capture_notify;
784 ops.destroy = audio_capture_destroy;
785 ops.capture = audio_capture;
786
787 vs->audio_cap = AUD_add_capture(NULL, &vs->as, &ops, vs);
788 if (!vs->audio_cap) {
789 term_printf ("Failed to add audio capture\n");
790 }
791}
792
793static void audio_del(VncState *vs)
794{
795 if (vs->audio_cap) {
796 AUD_del_capture(vs->audio_cap, vs);
797 vs->audio_cap = NULL;
798 }
799}
800
bellard6ca957f2006-04-30 22:53:25 +0000801static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
bellard24236862006-04-30 21:28:36 +0000802{
803 if (ret == 0 || ret == -1) {
balrogea01e5f2008-04-24 23:40:55 +0000804 if (ret == -1) {
805 switch (last_errno) {
806 case EINTR:
807 case EAGAIN:
808#ifdef _WIN32
809 case WSAEWOULDBLOCK:
810#endif
811 return 0;
812 default:
813 break;
814 }
815 }
bellard24236862006-04-30 21:28:36 +0000816
ths8d5d2d42007-08-25 01:37:51 +0000817 VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0);
bellard24236862006-04-30 21:28:36 +0000818 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
bellard6ca957f2006-04-30 22:53:25 +0000819 closesocket(vs->csock);
bellard24236862006-04-30 21:28:36 +0000820 vs->csock = -1;
aliguori7d957bd2009-01-15 22:14:11 +0000821 dcl->idle = 1;
bellard24236862006-04-30 21:28:36 +0000822 buffer_reset(&vs->input);
823 buffer_reset(&vs->output);
824 vs->need_update = 0;
blueswir1eb38c522008-09-06 17:47:39 +0000825#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000826 if (vs->tls_session) {
827 gnutls_deinit(vs->tls_session);
828 vs->tls_session = NULL;
829 }
830 vs->wiremode = VNC_WIREMODE_CLEAR;
831#endif /* CONFIG_VNC_TLS */
malc429a8ed2008-12-01 20:57:48 +0000832 audio_del(vs);
bellard24236862006-04-30 21:28:36 +0000833 return 0;
834 }
835 return ret;
836}
837
838static void vnc_client_error(VncState *vs)
839{
bellard6ca957f2006-04-30 22:53:25 +0000840 vnc_client_io_error(vs, -1, EINVAL);
bellard24236862006-04-30 21:28:36 +0000841}
842
843static void vnc_client_write(void *opaque)
844{
bellardceb5caa2006-05-03 21:18:59 +0000845 long ret;
bellard24236862006-04-30 21:28:36 +0000846 VncState *vs = opaque;
847
blueswir1eb38c522008-09-06 17:47:39 +0000848#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000849 if (vs->tls_session) {
850 ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset);
851 if (ret < 0) {
852 if (ret == GNUTLS_E_AGAIN)
853 errno = EAGAIN;
854 else
855 errno = EIO;
856 ret = -1;
857 }
858 } else
859#endif /* CONFIG_VNC_TLS */
860 ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
bellard6ca957f2006-04-30 22:53:25 +0000861 ret = vnc_client_io_error(vs, ret, socket_error());
bellard24236862006-04-30 21:28:36 +0000862 if (!ret)
863 return;
864
865 memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
866 vs->output.offset -= ret;
867
868 if (vs->output.offset == 0) {
869 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
870 }
871}
872
873static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
874{
875 vs->read_handler = func;
876 vs->read_handler_expect = expecting;
877}
878
879static void vnc_client_read(void *opaque)
880{
881 VncState *vs = opaque;
bellardceb5caa2006-05-03 21:18:59 +0000882 long ret;
bellard24236862006-04-30 21:28:36 +0000883
884 buffer_reserve(&vs->input, 4096);
885
blueswir1eb38c522008-09-06 17:47:39 +0000886#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +0000887 if (vs->tls_session) {
888 ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096);
889 if (ret < 0) {
890 if (ret == GNUTLS_E_AGAIN)
891 errno = EAGAIN;
892 else
893 errno = EIO;
894 ret = -1;
895 }
896 } else
897#endif /* CONFIG_VNC_TLS */
898 ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
bellard6ca957f2006-04-30 22:53:25 +0000899 ret = vnc_client_io_error(vs, ret, socket_error());
bellard24236862006-04-30 21:28:36 +0000900 if (!ret)
901 return;
902
903 vs->input.offset += ret;
904
905 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
906 size_t len = vs->read_handler_expect;
907 int ret;
908
909 ret = vs->read_handler(vs, vs->input.buffer, len);
910 if (vs->csock == -1)
911 return;
912
913 if (!ret) {
914 memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
915 vs->input.offset -= len;
916 } else {
917 vs->read_handler_expect = ret;
918 }
919 }
920}
921
922static void vnc_write(VncState *vs, const void *data, size_t len)
923{
924 buffer_reserve(&vs->output, len);
925
926 if (buffer_empty(&vs->output)) {
927 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
928 }
929
930 buffer_append(&vs->output, data, len);
931}
932
933static void vnc_write_s32(VncState *vs, int32_t value)
934{
935 vnc_write_u32(vs, *(uint32_t *)&value);
936}
937
938static void vnc_write_u32(VncState *vs, uint32_t value)
939{
940 uint8_t buf[4];
941
942 buf[0] = (value >> 24) & 0xFF;
943 buf[1] = (value >> 16) & 0xFF;
944 buf[2] = (value >> 8) & 0xFF;
945 buf[3] = value & 0xFF;
946
947 vnc_write(vs, buf, 4);
948}
949
950static void vnc_write_u16(VncState *vs, uint16_t value)
951{
bellard64f5a132006-08-24 20:36:44 +0000952 uint8_t buf[2];
bellard24236862006-04-30 21:28:36 +0000953
954 buf[0] = (value >> 8) & 0xFF;
955 buf[1] = value & 0xFF;
956
957 vnc_write(vs, buf, 2);
958}
959
960static void vnc_write_u8(VncState *vs, uint8_t value)
961{
962 vnc_write(vs, (char *)&value, 1);
963}
964
965static void vnc_flush(VncState *vs)
966{
967 if (vs->output.offset)
968 vnc_client_write(vs);
969}
970
bellard64f5a132006-08-24 20:36:44 +0000971static uint8_t read_u8(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +0000972{
973 return data[offset];
974}
975
bellard64f5a132006-08-24 20:36:44 +0000976static uint16_t read_u16(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +0000977{
978 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
979}
980
bellard64f5a132006-08-24 20:36:44 +0000981static int32_t read_s32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +0000982{
983 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
984 (data[offset + 2] << 8) | data[offset + 3]);
985}
986
bellard64f5a132006-08-24 20:36:44 +0000987static uint32_t read_u32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +0000988{
989 return ((data[offset] << 24) | (data[offset + 1] << 16) |
990 (data[offset + 2] << 8) | data[offset + 3]);
991}
992
blueswir1eb38c522008-09-06 17:47:39 +0000993#ifdef CONFIG_VNC_TLS
pbrook9596ebb2007-11-18 01:44:38 +0000994static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
995 const void *data,
996 size_t len) {
ths8d5d2d42007-08-25 01:37:51 +0000997 struct VncState *vs = (struct VncState *)transport;
998 int ret;
999
1000 retry:
1001 ret = send(vs->csock, data, len, 0);
1002 if (ret < 0) {
1003 if (errno == EINTR)
1004 goto retry;
1005 return -1;
1006 }
1007 return ret;
1008}
1009
1010
pbrook9596ebb2007-11-18 01:44:38 +00001011static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
1012 void *data,
1013 size_t len) {
ths8d5d2d42007-08-25 01:37:51 +00001014 struct VncState *vs = (struct VncState *)transport;
1015 int ret;
1016
1017 retry:
1018 ret = recv(vs->csock, data, len, 0);
1019 if (ret < 0) {
1020 if (errno == EINTR)
1021 goto retry;
1022 return -1;
1023 }
1024 return ret;
1025}
1026#endif /* CONFIG_VNC_TLS */
1027
ths60fe76f2007-12-16 03:02:09 +00001028static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
bellard24236862006-04-30 21:28:36 +00001029{
1030}
1031
bellard564c3372007-02-05 20:14:10 +00001032static void check_pointer_type_change(VncState *vs, int absolute)
1033{
aliguori29fa4ed2009-02-02 15:58:29 +00001034 if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
bellard564c3372007-02-05 20:14:10 +00001035 vnc_write_u8(vs, 0);
1036 vnc_write_u8(vs, 0);
1037 vnc_write_u16(vs, 1);
1038 vnc_framebuffer_update(vs, absolute, 0,
aliguori29fa4ed2009-02-02 15:58:29 +00001039 ds_get_width(vs->ds), ds_get_height(vs->ds),
1040 VNC_ENCODING_POINTER_TYPE_CHANGE);
bellard564c3372007-02-05 20:14:10 +00001041 vnc_flush(vs);
1042 }
1043 vs->absolute = absolute;
1044}
1045
bellard24236862006-04-30 21:28:36 +00001046static void pointer_event(VncState *vs, int button_mask, int x, int y)
1047{
1048 int buttons = 0;
1049 int dz = 0;
1050
1051 if (button_mask & 0x01)
1052 buttons |= MOUSE_EVENT_LBUTTON;
1053 if (button_mask & 0x02)
1054 buttons |= MOUSE_EVENT_MBUTTON;
1055 if (button_mask & 0x04)
1056 buttons |= MOUSE_EVENT_RBUTTON;
1057 if (button_mask & 0x08)
1058 dz = -1;
1059 if (button_mask & 0x10)
1060 dz = 1;
bellard564c3372007-02-05 20:14:10 +00001061
1062 if (vs->absolute) {
aliguori0e1f5a02008-11-24 19:29:13 +00001063 kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
1064 y * 0x7FFF / (ds_get_height(vs->ds) - 1),
bellard24236862006-04-30 21:28:36 +00001065 dz, buttons);
aliguori29fa4ed2009-02-02 15:58:29 +00001066 } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
bellard564c3372007-02-05 20:14:10 +00001067 x -= 0x7FFF;
1068 y -= 0x7FFF;
1069
1070 kbd_mouse_event(x, y, dz, buttons);
bellard24236862006-04-30 21:28:36 +00001071 } else {
bellard564c3372007-02-05 20:14:10 +00001072 if (vs->last_x != -1)
1073 kbd_mouse_event(x - vs->last_x,
1074 y - vs->last_y,
1075 dz, buttons);
1076 vs->last_x = x;
1077 vs->last_y = y;
bellard24236862006-04-30 21:28:36 +00001078 }
bellard564c3372007-02-05 20:14:10 +00001079
1080 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001081}
1082
bellard64f5a132006-08-24 20:36:44 +00001083static void reset_keys(VncState *vs)
1084{
1085 int i;
1086 for(i = 0; i < 256; i++) {
1087 if (vs->modifiers_state[i]) {
1088 if (i & 0x80)
1089 kbd_put_keycode(0xe0);
1090 kbd_put_keycode(i | 0x80);
1091 vs->modifiers_state[i] = 0;
1092 }
1093 }
1094}
1095
balroga528b802007-10-30 22:38:53 +00001096static void press_key(VncState *vs, int keysym)
1097{
1098 kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) & 0x7f);
1099 kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80);
1100}
1101
aliguori9ca313a2008-08-23 23:27:37 +00001102static void do_key_event(VncState *vs, int down, int keycode, int sym)
bellard24236862006-04-30 21:28:36 +00001103{
bellard64f5a132006-08-24 20:36:44 +00001104 /* QEMU console switch */
1105 switch(keycode) {
1106 case 0x2a: /* Left Shift */
1107 case 0x36: /* Right Shift */
1108 case 0x1d: /* Left CTRL */
1109 case 0x9d: /* Right CTRL */
1110 case 0x38: /* Left ALT */
1111 case 0xb8: /* Right ALT */
1112 if (down)
1113 vs->modifiers_state[keycode] = 1;
1114 else
1115 vs->modifiers_state[keycode] = 0;
1116 break;
ths5fafdf22007-09-16 21:08:06 +00001117 case 0x02 ... 0x0a: /* '1' to '9' keys */
bellard64f5a132006-08-24 20:36:44 +00001118 if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1119 /* Reset the modifiers sent to the current console */
1120 reset_keys(vs);
1121 console_select(keycode - 0x02);
1122 return;
1123 }
1124 break;
balrog4d3b6f62008-02-10 16:33:14 +00001125 case 0x3a: /* CapsLock */
balroga528b802007-10-30 22:38:53 +00001126 case 0x45: /* NumLock */
1127 if (!down)
1128 vs->modifiers_state[keycode] ^= 1;
1129 break;
1130 }
1131
1132 if (keycode_is_keypad(vs->kbd_layout, keycode)) {
1133 /* If the numlock state needs to change then simulate an additional
1134 keypress before sending this one. This will happen if the user
1135 toggles numlock away from the VNC window.
1136 */
1137 if (keysym_is_numlock(vs->kbd_layout, sym & 0xFFFF)) {
1138 if (!vs->modifiers_state[0x45]) {
1139 vs->modifiers_state[0x45] = 1;
1140 press_key(vs, 0xff7f);
1141 }
1142 } else {
1143 if (vs->modifiers_state[0x45]) {
1144 vs->modifiers_state[0x45] = 0;
1145 press_key(vs, 0xff7f);
1146 }
1147 }
bellard64f5a132006-08-24 20:36:44 +00001148 }
bellard24236862006-04-30 21:28:36 +00001149
bellard64f5a132006-08-24 20:36:44 +00001150 if (is_graphic_console()) {
1151 if (keycode & 0x80)
1152 kbd_put_keycode(0xe0);
1153 if (down)
1154 kbd_put_keycode(keycode & 0x7f);
1155 else
1156 kbd_put_keycode(keycode | 0x80);
1157 } else {
1158 /* QEMU console emulation */
1159 if (down) {
1160 switch (keycode) {
1161 case 0x2a: /* Left Shift */
1162 case 0x36: /* Right Shift */
1163 case 0x1d: /* Left CTRL */
1164 case 0x9d: /* Right CTRL */
1165 case 0x38: /* Left ALT */
1166 case 0xb8: /* Right ALT */
1167 break;
1168 case 0xc8:
1169 kbd_put_keysym(QEMU_KEY_UP);
1170 break;
1171 case 0xd0:
1172 kbd_put_keysym(QEMU_KEY_DOWN);
1173 break;
1174 case 0xcb:
1175 kbd_put_keysym(QEMU_KEY_LEFT);
1176 break;
1177 case 0xcd:
1178 kbd_put_keysym(QEMU_KEY_RIGHT);
1179 break;
1180 case 0xd3:
1181 kbd_put_keysym(QEMU_KEY_DELETE);
1182 break;
1183 case 0xc7:
1184 kbd_put_keysym(QEMU_KEY_HOME);
1185 break;
1186 case 0xcf:
1187 kbd_put_keysym(QEMU_KEY_END);
1188 break;
1189 case 0xc9:
1190 kbd_put_keysym(QEMU_KEY_PAGEUP);
1191 break;
1192 case 0xd1:
1193 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1194 break;
1195 default:
1196 kbd_put_keysym(sym);
1197 break;
1198 }
1199 }
1200 }
bellard24236862006-04-30 21:28:36 +00001201}
1202
bellardbdbd7672006-05-01 21:44:22 +00001203static void key_event(VncState *vs, int down, uint32_t sym)
1204{
aliguori9ca313a2008-08-23 23:27:37 +00001205 int keycode;
1206
balroga528b802007-10-30 22:38:53 +00001207 if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
bellardbdbd7672006-05-01 21:44:22 +00001208 sym = sym - 'A' + 'a';
aliguori9ca313a2008-08-23 23:27:37 +00001209
1210 keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
1211 do_key_event(vs, down, keycode, sym);
1212}
1213
1214static void ext_key_event(VncState *vs, int down,
1215 uint32_t sym, uint16_t keycode)
1216{
1217 /* if the user specifies a keyboard layout, always use it */
1218 if (keyboard_layout)
1219 key_event(vs, down, sym);
1220 else
1221 do_key_event(vs, down, keycode, sym);
bellardbdbd7672006-05-01 21:44:22 +00001222}
1223
bellard24236862006-04-30 21:28:36 +00001224static void framebuffer_update_request(VncState *vs, int incremental,
1225 int x_position, int y_position,
1226 int w, int h)
1227{
aliguori0e1f5a02008-11-24 19:29:13 +00001228 if (x_position > ds_get_width(vs->ds))
1229 x_position = ds_get_width(vs->ds);
1230 if (y_position > ds_get_height(vs->ds))
1231 y_position = ds_get_height(vs->ds);
1232 if (x_position + w >= ds_get_width(vs->ds))
1233 w = ds_get_width(vs->ds) - x_position;
1234 if (y_position + h >= ds_get_height(vs->ds))
1235 h = ds_get_height(vs->ds) - y_position;
thscf2d3852007-04-29 01:53:20 +00001236
bellard24236862006-04-30 21:28:36 +00001237 int i;
1238 vs->need_update = 1;
1239 if (!incremental) {
aliguori0e1f5a02008-11-24 19:29:13 +00001240 char *old_row = vs->old_data + y_position * ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +00001241
1242 for (i = 0; i < h; i++) {
ths5fafdf22007-09-16 21:08:06 +00001243 vnc_set_bits(vs->dirty_row[y_position + i],
aliguori0e1f5a02008-11-24 19:29:13 +00001244 (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
aliguori6cec5482009-01-15 22:17:38 +00001245 memset(old_row, 42, ds_get_width(vs->ds) * ds_get_bytes_per_pixel(vs->ds));
aliguori0e1f5a02008-11-24 19:29:13 +00001246 old_row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +00001247 }
1248 }
1249}
1250
aliguori9ca313a2008-08-23 23:27:37 +00001251static void send_ext_key_event_ack(VncState *vs)
1252{
1253 vnc_write_u8(vs, 0);
1254 vnc_write_u8(vs, 0);
1255 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001256 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1257 VNC_ENCODING_EXT_KEY_EVENT);
aliguori9ca313a2008-08-23 23:27:37 +00001258 vnc_flush(vs);
1259}
1260
malc429a8ed2008-12-01 20:57:48 +00001261static void send_ext_audio_ack(VncState *vs)
1262{
1263 vnc_write_u8(vs, 0);
1264 vnc_write_u8(vs, 0);
1265 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001266 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1267 VNC_ENCODING_AUDIO);
malc429a8ed2008-12-01 20:57:48 +00001268 vnc_flush(vs);
1269}
1270
bellard24236862006-04-30 21:28:36 +00001271static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1272{
1273 int i;
aliguori29fa4ed2009-02-02 15:58:29 +00001274 unsigned int enc = 0;
bellard24236862006-04-30 21:28:36 +00001275
aliguori059cef42009-02-02 15:58:54 +00001276 vnc_zlib_init(vs);
aliguori29fa4ed2009-02-02 15:58:29 +00001277 vs->features = 0;
aliguorifb437312009-02-02 15:58:43 +00001278 vs->vnc_encoding = 0;
1279 vs->tight_compression = 9;
1280 vs->tight_quality = 9;
bellard564c3372007-02-05 20:14:10 +00001281 vs->absolute = -1;
aliguori7d957bd2009-01-15 22:14:11 +00001282 dcl->dpy_copy = NULL;
bellard24236862006-04-30 21:28:36 +00001283
1284 for (i = n_encodings - 1; i >= 0; i--) {
aliguori29fa4ed2009-02-02 15:58:29 +00001285 enc = encodings[i];
1286 switch (enc) {
1287 case VNC_ENCODING_RAW:
aliguorifb437312009-02-02 15:58:43 +00001288 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001289 break;
1290 case VNC_ENCODING_COPYRECT:
1291 dcl->dpy_copy = vnc_copy;
1292 break;
1293 case VNC_ENCODING_HEXTILE:
1294 vs->features |= VNC_FEATURE_HEXTILE_MASK;
aliguorifb437312009-02-02 15:58:43 +00001295 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001296 break;
aliguori059cef42009-02-02 15:58:54 +00001297 case VNC_ENCODING_ZLIB:
1298 vs->features |= VNC_FEATURE_ZLIB_MASK;
1299 vs->vnc_encoding = enc;
1300 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001301 case VNC_ENCODING_DESKTOPRESIZE:
1302 vs->features |= VNC_FEATURE_RESIZE_MASK;
1303 break;
1304 case VNC_ENCODING_POINTER_TYPE_CHANGE:
1305 vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
1306 break;
1307 case VNC_ENCODING_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00001308 send_ext_key_event_ack(vs);
1309 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001310 case VNC_ENCODING_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00001311 send_ext_audio_ack(vs);
1312 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001313 case VNC_ENCODING_WMVi:
1314 vs->features |= VNC_FEATURE_WMVI_MASK;
aliguorica4cca42008-09-15 16:05:16 +00001315 break;
aliguorifb437312009-02-02 15:58:43 +00001316 case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
1317 vs->tight_compression = (enc & 0x0F);
1318 break;
1319 case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
1320 vs->tight_quality = (enc & 0x0F);
1321 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001322 default:
1323 VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
1324 break;
1325 }
bellard24236862006-04-30 21:28:36 +00001326 }
bellard564c3372007-02-05 20:14:10 +00001327
1328 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001329}
1330
aliguori6cec5482009-01-15 22:17:38 +00001331static void set_pixel_conversion(VncState *vs)
1332{
1333 if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
1334 (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) &&
1335 !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
1336 vs->write_pixels = vnc_write_pixels_copy;
1337 switch (vs->ds->surface->pf.bits_per_pixel) {
1338 case 8:
1339 vs->send_hextile_tile = send_hextile_tile_8;
1340 break;
1341 case 16:
1342 vs->send_hextile_tile = send_hextile_tile_16;
1343 break;
1344 case 32:
1345 vs->send_hextile_tile = send_hextile_tile_32;
1346 break;
1347 }
1348 } else {
1349 vs->write_pixels = vnc_write_pixels_generic;
1350 switch (vs->ds->surface->pf.bits_per_pixel) {
1351 case 8:
1352 vs->send_hextile_tile = send_hextile_tile_generic_8;
1353 break;
1354 case 16:
1355 vs->send_hextile_tile = send_hextile_tile_generic_16;
1356 break;
1357 case 32:
1358 vs->send_hextile_tile = send_hextile_tile_generic_32;
1359 break;
1360 }
1361 }
1362}
1363
bellard24236862006-04-30 21:28:36 +00001364static void set_pixel_format(VncState *vs,
1365 int bits_per_pixel, int depth,
1366 int big_endian_flag, int true_color_flag,
1367 int red_max, int green_max, int blue_max,
1368 int red_shift, int green_shift, int blue_shift)
1369{
bellard35127792006-05-14 18:11:49 +00001370 if (!true_color_flag) {
bellard24236862006-04-30 21:28:36 +00001371 vnc_client_error(vs);
bellard35127792006-05-14 18:11:49 +00001372 return;
1373 }
aliguori7eac3a82008-09-15 16:03:41 +00001374
aliguori6cec5482009-01-15 22:17:38 +00001375 vs->clientds = vs->serverds;
1376 vs->clientds.pf.rmax = red_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001377 count_bits(vs->clientds.pf.rbits, red_max);
aliguori6cec5482009-01-15 22:17:38 +00001378 vs->clientds.pf.rshift = red_shift;
1379 vs->clientds.pf.rmask = red_max << red_shift;
1380 vs->clientds.pf.gmax = green_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001381 count_bits(vs->clientds.pf.gbits, green_max);
aliguori6cec5482009-01-15 22:17:38 +00001382 vs->clientds.pf.gshift = green_shift;
1383 vs->clientds.pf.gmask = green_max << green_shift;
1384 vs->clientds.pf.bmax = blue_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001385 count_bits(vs->clientds.pf.bbits, blue_max);
aliguori6cec5482009-01-15 22:17:38 +00001386 vs->clientds.pf.bshift = blue_shift;
1387 vs->clientds.pf.bmask = blue_max << blue_shift;
1388 vs->clientds.pf.bits_per_pixel = bits_per_pixel;
1389 vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
1390 vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
1391 vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
bellard24236862006-04-30 21:28:36 +00001392
aliguori6cec5482009-01-15 22:17:38 +00001393 set_pixel_conversion(vs);
bellard24236862006-04-30 21:28:36 +00001394
1395 vga_hw_invalidate();
1396 vga_hw_update();
1397}
1398
aliguorica4cca42008-09-15 16:05:16 +00001399static void pixel_format_message (VncState *vs) {
1400 char pad[3] = { 0, 0, 0 };
1401
aliguori6cec5482009-01-15 22:17:38 +00001402 vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
1403 vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
aliguorica4cca42008-09-15 16:05:16 +00001404
1405#ifdef WORDS_BIGENDIAN
1406 vnc_write_u8(vs, 1); /* big-endian-flag */
1407#else
1408 vnc_write_u8(vs, 0); /* big-endian-flag */
1409#endif
1410 vnc_write_u8(vs, 1); /* true-color-flag */
aliguori6cec5482009-01-15 22:17:38 +00001411 vnc_write_u16(vs, vs->ds->surface->pf.rmax); /* red-max */
1412 vnc_write_u16(vs, vs->ds->surface->pf.gmax); /* green-max */
1413 vnc_write_u16(vs, vs->ds->surface->pf.bmax); /* blue-max */
1414 vnc_write_u8(vs, vs->ds->surface->pf.rshift); /* red-shift */
1415 vnc_write_u8(vs, vs->ds->surface->pf.gshift); /* green-shift */
1416 vnc_write_u8(vs, vs->ds->surface->pf.bshift); /* blue-shift */
1417 if (vs->ds->surface->pf.bits_per_pixel == 32)
aliguorica4cca42008-09-15 16:05:16 +00001418 vs->send_hextile_tile = send_hextile_tile_32;
aliguori6cec5482009-01-15 22:17:38 +00001419 else if (vs->ds->surface->pf.bits_per_pixel == 16)
aliguorica4cca42008-09-15 16:05:16 +00001420 vs->send_hextile_tile = send_hextile_tile_16;
aliguori6cec5482009-01-15 22:17:38 +00001421 else if (vs->ds->surface->pf.bits_per_pixel == 8)
aliguorica4cca42008-09-15 16:05:16 +00001422 vs->send_hextile_tile = send_hextile_tile_8;
aliguori6cec5482009-01-15 22:17:38 +00001423 vs->clientds = *(vs->ds->surface);
1424 vs->clientds.flags |= ~QEMU_ALLOCATED_FLAG;
aliguorica4cca42008-09-15 16:05:16 +00001425 vs->write_pixels = vnc_write_pixels_copy;
1426
1427 vnc_write(vs, pad, 3); /* padding */
1428}
1429
aliguori7d957bd2009-01-15 22:14:11 +00001430static void vnc_dpy_setdata(DisplayState *ds)
1431{
1432 /* We don't have to do anything */
1433}
1434
1435static void vnc_colordepth(DisplayState *ds)
aliguori7eac3a82008-09-15 16:03:41 +00001436{
aliguori7eac3a82008-09-15 16:03:41 +00001437 struct VncState *vs = ds->opaque;
1438
aliguori29fa4ed2009-02-02 15:58:29 +00001439 if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
aliguorica4cca42008-09-15 16:05:16 +00001440 /* Sending a WMVi message to notify the client*/
1441 vnc_write_u8(vs, 0); /* msg id */
1442 vnc_write_u8(vs, 0);
1443 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +00001444 vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
1445 VNC_ENCODING_WMVi);
aliguorica4cca42008-09-15 16:05:16 +00001446 pixel_format_message(vs);
1447 vnc_flush(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001448 } else {
aliguori6cec5482009-01-15 22:17:38 +00001449 set_pixel_conversion(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001450 }
1451}
1452
ths60fe76f2007-12-16 03:02:09 +00001453static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001454{
1455 int i;
1456 uint16_t limit;
1457
1458 switch (data[0]) {
1459 case 0:
1460 if (len == 1)
1461 return 20;
1462
1463 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
1464 read_u8(data, 6), read_u8(data, 7),
1465 read_u16(data, 8), read_u16(data, 10),
1466 read_u16(data, 12), read_u8(data, 14),
1467 read_u8(data, 15), read_u8(data, 16));
1468 break;
1469 case 2:
1470 if (len == 1)
1471 return 4;
1472
aliguori69dd5c92008-12-22 21:06:23 +00001473 if (len == 4) {
1474 limit = read_u16(data, 2);
1475 if (limit > 0)
1476 return 4 + (limit * 4);
1477 } else
1478 limit = read_u16(data, 2);
bellard24236862006-04-30 21:28:36 +00001479
bellard24236862006-04-30 21:28:36 +00001480 for (i = 0; i < limit; i++) {
1481 int32_t val = read_s32(data, 4 + (i * 4));
1482 memcpy(data + 4 + (i * 4), &val, sizeof(val));
1483 }
1484
1485 set_encodings(vs, (int32_t *)(data + 4), limit);
1486 break;
1487 case 3:
1488 if (len == 1)
1489 return 10;
1490
1491 framebuffer_update_request(vs,
1492 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
1493 read_u16(data, 6), read_u16(data, 8));
1494 break;
1495 case 4:
1496 if (len == 1)
1497 return 8;
1498
1499 key_event(vs, read_u8(data, 1), read_u32(data, 4));
1500 break;
1501 case 5:
1502 if (len == 1)
1503 return 6;
1504
1505 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
1506 break;
1507 case 6:
1508 if (len == 1)
1509 return 8;
1510
thsbaa76662007-09-13 12:41:42 +00001511 if (len == 8) {
1512 uint32_t dlen = read_u32(data, 4);
1513 if (dlen > 0)
1514 return 8 + dlen;
1515 }
bellard24236862006-04-30 21:28:36 +00001516
1517 client_cut_text(vs, read_u32(data, 4), data + 8);
1518 break;
aliguori9ca313a2008-08-23 23:27:37 +00001519 case 255:
1520 if (len == 1)
1521 return 2;
1522
1523 switch (read_u8(data, 1)) {
1524 case 0:
1525 if (len == 2)
1526 return 12;
1527
1528 ext_key_event(vs, read_u16(data, 2),
1529 read_u32(data, 4), read_u32(data, 8));
1530 break;
malc429a8ed2008-12-01 20:57:48 +00001531 case 1:
1532 if (len == 2)
1533 return 4;
1534
1535 switch (read_u16 (data, 2)) {
1536 case 0:
1537 audio_add(vs);
1538 break;
1539 case 1:
1540 audio_del(vs);
1541 break;
1542 case 2:
1543 if (len == 4)
1544 return 10;
1545 switch (read_u8(data, 4)) {
1546 case 0: vs->as.fmt = AUD_FMT_U8; break;
1547 case 1: vs->as.fmt = AUD_FMT_S8; break;
1548 case 2: vs->as.fmt = AUD_FMT_U16; break;
1549 case 3: vs->as.fmt = AUD_FMT_S16; break;
1550 case 4: vs->as.fmt = AUD_FMT_U32; break;
1551 case 5: vs->as.fmt = AUD_FMT_S32; break;
1552 default:
1553 printf("Invalid audio format %d\n", read_u8(data, 4));
1554 vnc_client_error(vs);
1555 break;
1556 }
1557 vs->as.nchannels = read_u8(data, 5);
1558 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
1559 printf("Invalid audio channel coount %d\n",
1560 read_u8(data, 5));
1561 vnc_client_error(vs);
1562 break;
1563 }
1564 vs->as.freq = read_u32(data, 6);
1565 break;
1566 default:
1567 printf ("Invalid audio message %d\n", read_u8(data, 4));
1568 vnc_client_error(vs);
1569 break;
1570 }
1571 break;
1572
aliguori9ca313a2008-08-23 23:27:37 +00001573 default:
1574 printf("Msg: %d\n", read_u16(data, 0));
1575 vnc_client_error(vs);
1576 break;
1577 }
1578 break;
bellard24236862006-04-30 21:28:36 +00001579 default:
1580 printf("Msg: %d\n", data[0]);
1581 vnc_client_error(vs);
1582 break;
1583 }
ths5fafdf22007-09-16 21:08:06 +00001584
bellard24236862006-04-30 21:28:36 +00001585 vnc_read_when(vs, protocol_client_msg, 1);
1586 return 0;
1587}
1588
ths60fe76f2007-12-16 03:02:09 +00001589static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001590{
thsc35734b2007-03-19 15:17:08 +00001591 char buf[1024];
1592 int size;
bellard24236862006-04-30 21:28:36 +00001593
aliguori0e1f5a02008-11-24 19:29:13 +00001594 vnc_write_u16(vs, ds_get_width(vs->ds));
1595 vnc_write_u16(vs, ds_get_height(vs->ds));
bellard24236862006-04-30 21:28:36 +00001596
aliguorica4cca42008-09-15 16:05:16 +00001597 pixel_format_message(vs);
bellard24236862006-04-30 21:28:36 +00001598
thsc35734b2007-03-19 15:17:08 +00001599 if (qemu_name)
1600 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
1601 else
1602 size = snprintf(buf, sizeof(buf), "QEMU");
1603
1604 vnc_write_u32(vs, size);
1605 vnc_write(vs, buf, size);
bellard24236862006-04-30 21:28:36 +00001606 vnc_flush(vs);
1607
1608 vnc_read_when(vs, protocol_client_msg, 1);
1609
1610 return 0;
1611}
1612
ths70848512007-08-25 01:37:05 +00001613static void make_challenge(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001614{
ths70848512007-08-25 01:37:05 +00001615 int i;
bellard24236862006-04-30 21:28:36 +00001616
ths70848512007-08-25 01:37:05 +00001617 srand(time(NULL)+getpid()+getpid()*987654+rand());
bellard24236862006-04-30 21:28:36 +00001618
ths70848512007-08-25 01:37:05 +00001619 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
1620 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
1621}
1622
ths60fe76f2007-12-16 03:02:09 +00001623static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00001624{
ths60fe76f2007-12-16 03:02:09 +00001625 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
ths70848512007-08-25 01:37:05 +00001626 int i, j, pwlen;
ths60fe76f2007-12-16 03:02:09 +00001627 unsigned char key[8];
ths70848512007-08-25 01:37:05 +00001628
1629 if (!vs->password || !vs->password[0]) {
1630 VNC_DEBUG("No password configured on server");
1631 vnc_write_u32(vs, 1); /* Reject auth */
1632 if (vs->minor >= 8) {
1633 static const char err[] = "Authentication failed";
1634 vnc_write_u32(vs, sizeof(err));
1635 vnc_write(vs, err, sizeof(err));
1636 }
1637 vnc_flush(vs);
bellard24236862006-04-30 21:28:36 +00001638 vnc_client_error(vs);
1639 return 0;
1640 }
1641
ths70848512007-08-25 01:37:05 +00001642 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
1643
1644 /* Calculate the expected challenge response */
1645 pwlen = strlen(vs->password);
1646 for (i=0; i<sizeof(key); i++)
1647 key[i] = i<pwlen ? vs->password[i] : 0;
1648 deskey(key, EN0);
1649 for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
1650 des(response+j, response+j);
1651
1652 /* Compare expected vs actual challenge response */
1653 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
1654 VNC_DEBUG("Client challenge reponse did not match\n");
1655 vnc_write_u32(vs, 1); /* Reject auth */
1656 if (vs->minor >= 8) {
1657 static const char err[] = "Authentication failed";
1658 vnc_write_u32(vs, sizeof(err));
1659 vnc_write(vs, err, sizeof(err));
1660 }
1661 vnc_flush(vs);
1662 vnc_client_error(vs);
1663 } else {
1664 VNC_DEBUG("Accepting VNC challenge response\n");
1665 vnc_write_u32(vs, 0); /* Accept auth */
1666 vnc_flush(vs);
1667
1668 vnc_read_when(vs, protocol_client_init, 1);
1669 }
1670 return 0;
1671}
1672
1673static int start_auth_vnc(VncState *vs)
1674{
1675 make_challenge(vs);
1676 /* Send client a 'random' challenge */
1677 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
bellard24236862006-04-30 21:28:36 +00001678 vnc_flush(vs);
1679
ths70848512007-08-25 01:37:05 +00001680 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
1681 return 0;
1682}
1683
ths8d5d2d42007-08-25 01:37:51 +00001684
blueswir1eb38c522008-09-06 17:47:39 +00001685#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00001686#define DH_BITS 1024
1687static gnutls_dh_params_t dh_params;
1688
1689static int vnc_tls_initialize(void)
1690{
1691 static int tlsinitialized = 0;
1692
1693 if (tlsinitialized)
1694 return 1;
1695
1696 if (gnutls_global_init () < 0)
1697 return 0;
1698
1699 /* XXX ought to re-generate diffie-hellmen params periodically */
1700 if (gnutls_dh_params_init (&dh_params) < 0)
1701 return 0;
1702 if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
1703 return 0;
1704
ths234c9bc2008-09-24 15:17:57 +00001705#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
ths8d5d2d42007-08-25 01:37:51 +00001706 gnutls_global_set_log_level(10);
1707 gnutls_global_set_log_function(vnc_debug_gnutls_log);
1708#endif
1709
1710 tlsinitialized = 1;
1711
1712 return 1;
1713}
1714
1715static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
1716{
1717 gnutls_anon_server_credentials anon_cred;
1718 int ret;
1719
1720 if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
1721 VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
1722 return NULL;
1723 }
1724
1725 gnutls_anon_set_server_dh_params(anon_cred, dh_params);
1726
1727 return anon_cred;
1728}
1729
1730
ths6f430242007-08-25 01:39:57 +00001731static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs)
ths3a702692007-08-25 01:38:36 +00001732{
1733 gnutls_certificate_credentials_t x509_cred;
1734 int ret;
ths6f430242007-08-25 01:39:57 +00001735
1736 if (!vs->x509cacert) {
1737 VNC_DEBUG("No CA x509 certificate specified\n");
1738 return NULL;
1739 }
1740 if (!vs->x509cert) {
1741 VNC_DEBUG("No server x509 certificate specified\n");
1742 return NULL;
1743 }
1744 if (!vs->x509key) {
1745 VNC_DEBUG("No server private key specified\n");
1746 return NULL;
1747 }
ths3a702692007-08-25 01:38:36 +00001748
1749 if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
1750 VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
1751 return NULL;
1752 }
ths6f430242007-08-25 01:39:57 +00001753 if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
1754 vs->x509cacert,
1755 GNUTLS_X509_FMT_PEM)) < 0) {
ths3a702692007-08-25 01:38:36 +00001756 VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
1757 gnutls_certificate_free_credentials(x509_cred);
1758 return NULL;
1759 }
1760
ths6f430242007-08-25 01:39:57 +00001761 if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
1762 vs->x509cert,
1763 vs->x509key,
ths3a702692007-08-25 01:38:36 +00001764 GNUTLS_X509_FMT_PEM)) < 0) {
1765 VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
1766 gnutls_certificate_free_credentials(x509_cred);
1767 return NULL;
1768 }
1769
ths6f430242007-08-25 01:39:57 +00001770 if (vs->x509cacrl) {
1771 if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
1772 vs->x509cacrl,
1773 GNUTLS_X509_FMT_PEM)) < 0) {
ths3a702692007-08-25 01:38:36 +00001774 VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
1775 gnutls_certificate_free_credentials(x509_cred);
1776 return NULL;
1777 }
1778 }
1779
1780 gnutls_certificate_set_dh_params (x509_cred, dh_params);
1781
1782 return x509_cred;
1783}
1784
ths469b15c2007-08-25 01:39:10 +00001785static int vnc_validate_certificate(struct VncState *vs)
1786{
1787 int ret;
1788 unsigned int status;
1789 const gnutls_datum_t *certs;
1790 unsigned int nCerts, i;
1791 time_t now;
1792
1793 VNC_DEBUG("Validating client certificate\n");
1794 if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) {
1795 VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
1796 return -1;
1797 }
1798
1799 if ((now = time(NULL)) == ((time_t)-1)) {
1800 return -1;
1801 }
1802
1803 if (status != 0) {
1804 if (status & GNUTLS_CERT_INVALID)
1805 VNC_DEBUG("The certificate is not trusted.\n");
1806
1807 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
1808 VNC_DEBUG("The certificate hasn't got a known issuer.\n");
1809
1810 if (status & GNUTLS_CERT_REVOKED)
1811 VNC_DEBUG("The certificate has been revoked.\n");
1812
1813 if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
1814 VNC_DEBUG("The certificate uses an insecure algorithm\n");
1815
1816 return -1;
1817 } else {
1818 VNC_DEBUG("Certificate is valid!\n");
1819 }
1820
1821 /* Only support x509 for now */
1822 if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509)
1823 return -1;
1824
1825 if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts)))
1826 return -1;
1827
1828 for (i = 0 ; i < nCerts ; i++) {
1829 gnutls_x509_crt_t cert;
1830 VNC_DEBUG ("Checking certificate chain %d\n", i);
1831 if (gnutls_x509_crt_init (&cert) < 0)
1832 return -1;
1833
1834 if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
1835 gnutls_x509_crt_deinit (cert);
1836 return -1;
1837 }
1838
1839 if (gnutls_x509_crt_get_expiration_time (cert) < now) {
1840 VNC_DEBUG("The certificate has expired\n");
1841 gnutls_x509_crt_deinit (cert);
1842 return -1;
1843 }
1844
1845 if (gnutls_x509_crt_get_activation_time (cert) > now) {
1846 VNC_DEBUG("The certificate is not yet activated\n");
1847 gnutls_x509_crt_deinit (cert);
1848 return -1;
1849 }
1850
1851 if (gnutls_x509_crt_get_activation_time (cert) > now) {
1852 VNC_DEBUG("The certificate is not yet activated\n");
1853 gnutls_x509_crt_deinit (cert);
1854 return -1;
1855 }
1856
1857 gnutls_x509_crt_deinit (cert);
1858 }
1859
1860 return 0;
1861}
1862
1863
ths8d5d2d42007-08-25 01:37:51 +00001864static int start_auth_vencrypt_subauth(VncState *vs)
1865{
1866 switch (vs->subauth) {
1867 case VNC_AUTH_VENCRYPT_TLSNONE:
ths3a702692007-08-25 01:38:36 +00001868 case VNC_AUTH_VENCRYPT_X509NONE:
ths8d5d2d42007-08-25 01:37:51 +00001869 VNC_DEBUG("Accept TLS auth none\n");
1870 vnc_write_u32(vs, 0); /* Accept auth completion */
1871 vnc_read_when(vs, protocol_client_init, 1);
1872 break;
1873
1874 case VNC_AUTH_VENCRYPT_TLSVNC:
ths3a702692007-08-25 01:38:36 +00001875 case VNC_AUTH_VENCRYPT_X509VNC:
ths8d5d2d42007-08-25 01:37:51 +00001876 VNC_DEBUG("Start TLS auth VNC\n");
1877 return start_auth_vnc(vs);
1878
1879 default: /* Should not be possible, but just in case */
1880 VNC_DEBUG("Reject auth %d\n", vs->auth);
1881 vnc_write_u8(vs, 1);
1882 if (vs->minor >= 8) {
1883 static const char err[] = "Unsupported authentication type";
1884 vnc_write_u32(vs, sizeof(err));
1885 vnc_write(vs, err, sizeof(err));
1886 }
1887 vnc_client_error(vs);
1888 }
1889
1890 return 0;
1891}
1892
1893static void vnc_handshake_io(void *opaque);
1894
1895static int vnc_continue_handshake(struct VncState *vs) {
1896 int ret;
1897
1898 if ((ret = gnutls_handshake(vs->tls_session)) < 0) {
1899 if (!gnutls_error_is_fatal(ret)) {
1900 VNC_DEBUG("Handshake interrupted (blocking)\n");
1901 if (!gnutls_record_get_direction(vs->tls_session))
1902 qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs);
1903 else
1904 qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs);
1905 return 0;
1906 }
1907 VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
1908 vnc_client_error(vs);
1909 return -1;
1910 }
1911
ths469b15c2007-08-25 01:39:10 +00001912 if (vs->x509verify) {
1913 if (vnc_validate_certificate(vs) < 0) {
1914 VNC_DEBUG("Client verification failed\n");
1915 vnc_client_error(vs);
1916 return -1;
1917 } else {
1918 VNC_DEBUG("Client verification passed\n");
1919 }
1920 }
1921
ths8d5d2d42007-08-25 01:37:51 +00001922 VNC_DEBUG("Handshake done, switching to TLS data mode\n");
1923 vs->wiremode = VNC_WIREMODE_TLS;
1924 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
1925
1926 return start_auth_vencrypt_subauth(vs);
1927}
1928
1929static void vnc_handshake_io(void *opaque) {
1930 struct VncState *vs = (struct VncState *)opaque;
1931
1932 VNC_DEBUG("Handshake IO continue\n");
1933 vnc_continue_handshake(vs);
1934}
1935
ths3a702692007-08-25 01:38:36 +00001936#define NEED_X509_AUTH(vs) \
1937 ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \
1938 (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \
1939 (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
1940
1941
ths8d5d2d42007-08-25 01:37:51 +00001942static int vnc_start_tls(struct VncState *vs) {
1943 static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
1944 static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
1945 static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
ths3a702692007-08-25 01:38:36 +00001946 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 +00001947
1948 VNC_DEBUG("Do TLS setup\n");
1949 if (vnc_tls_initialize() < 0) {
1950 VNC_DEBUG("Failed to init TLS\n");
1951 vnc_client_error(vs);
1952 return -1;
1953 }
1954 if (vs->tls_session == NULL) {
1955 if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) {
1956 vnc_client_error(vs);
1957 return -1;
1958 }
1959
1960 if (gnutls_set_default_priority(vs->tls_session) < 0) {
1961 gnutls_deinit(vs->tls_session);
1962 vs->tls_session = NULL;
1963 vnc_client_error(vs);
1964 return -1;
1965 }
1966
ths3a702692007-08-25 01:38:36 +00001967 if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) {
ths8d5d2d42007-08-25 01:37:51 +00001968 gnutls_deinit(vs->tls_session);
1969 vs->tls_session = NULL;
1970 vnc_client_error(vs);
1971 return -1;
1972 }
1973
1974 if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) {
1975 gnutls_deinit(vs->tls_session);
1976 vs->tls_session = NULL;
1977 vnc_client_error(vs);
1978 return -1;
1979 }
1980
1981 if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) {
1982 gnutls_deinit(vs->tls_session);
1983 vs->tls_session = NULL;
1984 vnc_client_error(vs);
1985 return -1;
1986 }
1987
ths3a702692007-08-25 01:38:36 +00001988 if (NEED_X509_AUTH(vs)) {
ths6f430242007-08-25 01:39:57 +00001989 gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs);
ths3a702692007-08-25 01:38:36 +00001990 if (!x509_cred) {
1991 gnutls_deinit(vs->tls_session);
1992 vs->tls_session = NULL;
1993 vnc_client_error(vs);
1994 return -1;
1995 }
1996 if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
1997 gnutls_deinit(vs->tls_session);
1998 vs->tls_session = NULL;
1999 gnutls_certificate_free_credentials(x509_cred);
2000 vnc_client_error(vs);
2001 return -1;
2002 }
ths469b15c2007-08-25 01:39:10 +00002003 if (vs->x509verify) {
2004 VNC_DEBUG("Requesting a client certificate\n");
2005 gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
2006 }
2007
ths3a702692007-08-25 01:38:36 +00002008 } else {
2009 gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
2010 if (!anon_cred) {
2011 gnutls_deinit(vs->tls_session);
2012 vs->tls_session = NULL;
2013 vnc_client_error(vs);
2014 return -1;
2015 }
2016 if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
2017 gnutls_deinit(vs->tls_session);
2018 vs->tls_session = NULL;
2019 gnutls_anon_free_server_credentials(anon_cred);
2020 vnc_client_error(vs);
2021 return -1;
2022 }
ths8d5d2d42007-08-25 01:37:51 +00002023 }
2024
2025 gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs);
2026 gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push);
2027 gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull);
2028 }
2029
2030 VNC_DEBUG("Start TLS handshake process\n");
2031 return vnc_continue_handshake(vs);
2032}
2033
ths60fe76f2007-12-16 03:02:09 +00002034static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
ths8d5d2d42007-08-25 01:37:51 +00002035{
2036 int auth = read_u32(data, 0);
2037
2038 if (auth != vs->subauth) {
2039 VNC_DEBUG("Rejecting auth %d\n", auth);
2040 vnc_write_u8(vs, 0); /* Reject auth */
2041 vnc_flush(vs);
2042 vnc_client_error(vs);
2043 } else {
2044 VNC_DEBUG("Accepting auth %d, starting handshake\n", auth);
2045 vnc_write_u8(vs, 1); /* Accept auth */
2046 vnc_flush(vs);
2047
2048 if (vnc_start_tls(vs) < 0) {
2049 VNC_DEBUG("Failed to complete TLS\n");
2050 return 0;
2051 }
2052
2053 if (vs->wiremode == VNC_WIREMODE_TLS) {
2054 VNC_DEBUG("Starting VeNCrypt subauth\n");
2055 return start_auth_vencrypt_subauth(vs);
2056 } else {
2057 VNC_DEBUG("TLS handshake blocked\n");
2058 return 0;
2059 }
2060 }
2061 return 0;
2062}
2063
ths60fe76f2007-12-16 03:02:09 +00002064static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
ths8d5d2d42007-08-25 01:37:51 +00002065{
2066 if (data[0] != 0 ||
2067 data[1] != 2) {
2068 VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
2069 vnc_write_u8(vs, 1); /* Reject version */
2070 vnc_flush(vs);
2071 vnc_client_error(vs);
2072 } else {
2073 VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
2074 vnc_write_u8(vs, 0); /* Accept version */
2075 vnc_write_u8(vs, 1); /* Number of sub-auths */
2076 vnc_write_u32(vs, vs->subauth); /* The supported auth */
2077 vnc_flush(vs);
2078 vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
2079 }
2080 return 0;
2081}
2082
2083static int start_auth_vencrypt(VncState *vs)
2084{
2085 /* Send VeNCrypt version 0.2 */
2086 vnc_write_u8(vs, 0);
2087 vnc_write_u8(vs, 2);
2088
2089 vnc_read_when(vs, protocol_client_vencrypt_init, 2);
2090 return 0;
2091}
2092#endif /* CONFIG_VNC_TLS */
2093
ths60fe76f2007-12-16 03:02:09 +00002094static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002095{
2096 /* We only advertise 1 auth scheme at a time, so client
2097 * must pick the one we sent. Verify this */
2098 if (data[0] != vs->auth) { /* Reject auth */
2099 VNC_DEBUG("Reject auth %d\n", (int)data[0]);
2100 vnc_write_u32(vs, 1);
2101 if (vs->minor >= 8) {
2102 static const char err[] = "Authentication failed";
2103 vnc_write_u32(vs, sizeof(err));
2104 vnc_write(vs, err, sizeof(err));
2105 }
2106 vnc_client_error(vs);
2107 } else { /* Accept requested auth */
2108 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
2109 switch (vs->auth) {
2110 case VNC_AUTH_NONE:
2111 VNC_DEBUG("Accept auth none\n");
balroga26c97a2007-10-31 01:58:56 +00002112 if (vs->minor >= 8) {
2113 vnc_write_u32(vs, 0); /* Accept auth completion */
2114 vnc_flush(vs);
2115 }
ths70848512007-08-25 01:37:05 +00002116 vnc_read_when(vs, protocol_client_init, 1);
2117 break;
2118
2119 case VNC_AUTH_VNC:
2120 VNC_DEBUG("Start VNC auth\n");
2121 return start_auth_vnc(vs);
2122
blueswir1eb38c522008-09-06 17:47:39 +00002123#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002124 case VNC_AUTH_VENCRYPT:
2125 VNC_DEBUG("Accept VeNCrypt auth\n");;
2126 return start_auth_vencrypt(vs);
2127#endif /* CONFIG_VNC_TLS */
2128
ths70848512007-08-25 01:37:05 +00002129 default: /* Should not be possible, but just in case */
2130 VNC_DEBUG("Reject auth %d\n", vs->auth);
2131 vnc_write_u8(vs, 1);
2132 if (vs->minor >= 8) {
2133 static const char err[] = "Authentication failed";
2134 vnc_write_u32(vs, sizeof(err));
2135 vnc_write(vs, err, sizeof(err));
2136 }
2137 vnc_client_error(vs);
2138 }
2139 }
2140 return 0;
2141}
2142
ths60fe76f2007-12-16 03:02:09 +00002143static int protocol_version(VncState *vs, uint8_t *version, size_t len)
ths70848512007-08-25 01:37:05 +00002144{
2145 char local[13];
2146
2147 memcpy(local, version, 12);
2148 local[12] = 0;
2149
2150 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
2151 VNC_DEBUG("Malformed protocol version %s\n", local);
2152 vnc_client_error(vs);
2153 return 0;
2154 }
2155 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2156 if (vs->major != 3 ||
2157 (vs->minor != 3 &&
thsb0566f42007-09-30 13:01:15 +00002158 vs->minor != 4 &&
ths70848512007-08-25 01:37:05 +00002159 vs->minor != 5 &&
2160 vs->minor != 7 &&
2161 vs->minor != 8)) {
2162 VNC_DEBUG("Unsupported client version\n");
2163 vnc_write_u32(vs, VNC_AUTH_INVALID);
2164 vnc_flush(vs);
2165 vnc_client_error(vs);
2166 return 0;
2167 }
thsb0566f42007-09-30 13:01:15 +00002168 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
ths70848512007-08-25 01:37:05 +00002169 * as equivalent to v3.3 by servers
2170 */
thsb0566f42007-09-30 13:01:15 +00002171 if (vs->minor == 4 || vs->minor == 5)
ths70848512007-08-25 01:37:05 +00002172 vs->minor = 3;
2173
2174 if (vs->minor == 3) {
2175 if (vs->auth == VNC_AUTH_NONE) {
2176 VNC_DEBUG("Tell client auth none\n");
2177 vnc_write_u32(vs, vs->auth);
2178 vnc_flush(vs);
2179 vnc_read_when(vs, protocol_client_init, 1);
2180 } else if (vs->auth == VNC_AUTH_VNC) {
2181 VNC_DEBUG("Tell client VNC auth\n");
2182 vnc_write_u32(vs, vs->auth);
2183 vnc_flush(vs);
2184 start_auth_vnc(vs);
2185 } else {
2186 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
2187 vnc_write_u32(vs, VNC_AUTH_INVALID);
2188 vnc_flush(vs);
2189 vnc_client_error(vs);
2190 }
2191 } else {
2192 VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
2193 vnc_write_u8(vs, 1); /* num auth */
2194 vnc_write_u8(vs, vs->auth);
2195 vnc_read_when(vs, protocol_client_auth, 1);
2196 vnc_flush(vs);
2197 }
bellard24236862006-04-30 21:28:36 +00002198
2199 return 0;
2200}
2201
balrog3aa3eea2008-02-03 02:54:04 +00002202static void vnc_connect(VncState *vs)
2203{
2204 VNC_DEBUG("New client on socket %d\n", vs->csock);
aliguori7d957bd2009-01-15 22:14:11 +00002205 dcl->idle = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002206 socket_set_nonblock(vs->csock);
2207 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
2208 vnc_write(vs, "RFB 003.008\n", 12);
2209 vnc_flush(vs);
2210 vnc_read_when(vs, protocol_version, 12);
aliguori0e1f5a02008-11-24 19:29:13 +00002211 memset(vs->old_data, 0, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
balrog3aa3eea2008-02-03 02:54:04 +00002212 memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
aliguori29fa4ed2009-02-02 15:58:29 +00002213 vs->features = 0;
aliguori7d957bd2009-01-15 22:14:11 +00002214 dcl->dpy_copy = NULL;
balrog3aa3eea2008-02-03 02:54:04 +00002215 vnc_update_client(vs);
malc53762dd2008-12-01 20:57:52 +00002216 reset_keys(vs);
balrog3aa3eea2008-02-03 02:54:04 +00002217}
2218
bellard24236862006-04-30 21:28:36 +00002219static void vnc_listen_read(void *opaque)
2220{
2221 VncState *vs = opaque;
2222 struct sockaddr_in addr;
2223 socklen_t addrlen = sizeof(addr);
2224
balrog9f60ad52008-01-14 21:45:55 +00002225 /* Catch-up */
2226 vga_hw_update();
2227
bellard24236862006-04-30 21:28:36 +00002228 vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
2229 if (vs->csock != -1) {
balrog3aa3eea2008-02-03 02:54:04 +00002230 vnc_connect(vs);
bellard24236862006-04-30 21:28:36 +00002231 }
2232}
2233
ths71cab5c2007-08-25 01:35:38 +00002234void vnc_display_init(DisplayState *ds)
bellard24236862006-04-30 21:28:36 +00002235{
bellard24236862006-04-30 21:28:36 +00002236 VncState *vs;
2237
2238 vs = qemu_mallocz(sizeof(VncState));
aliguori7d957bd2009-01-15 22:14:11 +00002239 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
bellard24236862006-04-30 21:28:36 +00002240
2241 ds->opaque = vs;
aliguori7d957bd2009-01-15 22:14:11 +00002242 dcl->idle = 1;
bellarda9ce8592007-02-05 20:20:30 +00002243 vnc_state = vs;
ths71cab5c2007-08-25 01:35:38 +00002244 vs->display = NULL;
ths70848512007-08-25 01:37:05 +00002245 vs->password = NULL;
bellard24236862006-04-30 21:28:36 +00002246
2247 vs->lsock = -1;
2248 vs->csock = -1;
bellard564c3372007-02-05 20:14:10 +00002249 vs->last_x = -1;
2250 vs->last_y = -1;
bellard24236862006-04-30 21:28:36 +00002251
2252 vs->ds = ds;
2253
aliguori9ca313a2008-08-23 23:27:37 +00002254 if (keyboard_layout)
2255 vs->kbd_layout = init_keyboard_layout(keyboard_layout);
2256 else
2257 vs->kbd_layout = init_keyboard_layout("en-us");
bellard24236862006-04-30 21:28:36 +00002258
bellard24236862006-04-30 21:28:36 +00002259 if (!vs->kbd_layout)
2260 exit(1);
2261
balroga0ecfb72008-01-13 23:51:53 +00002262 vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
2263
aliguori7d957bd2009-01-15 22:14:11 +00002264 dcl->dpy_update = vnc_dpy_update;
2265 dcl->dpy_resize = vnc_dpy_resize;
2266 dcl->dpy_setdata = vnc_dpy_setdata;
2267 dcl->dpy_refresh = NULL;
2268 register_displaychangelistener(ds, dcl);
malc429a8ed2008-12-01 20:57:48 +00002269
2270 vs->as.freq = 44100;
2271 vs->as.nchannels = 2;
2272 vs->as.fmt = AUD_FMT_S16;
2273 vs->as.endianness = 0;
ths71cab5c2007-08-25 01:35:38 +00002274}
ths73fc9742006-12-22 02:09:07 +00002275
blueswir1eb38c522008-09-06 17:47:39 +00002276#ifdef CONFIG_VNC_TLS
ths6f430242007-08-25 01:39:57 +00002277static int vnc_set_x509_credential(VncState *vs,
2278 const char *certdir,
2279 const char *filename,
2280 char **cred,
2281 int ignoreMissing)
2282{
2283 struct stat sb;
2284
2285 if (*cred) {
2286 qemu_free(*cred);
2287 *cred = NULL;
2288 }
2289
aliguori1eec6142009-02-05 22:06:18 +00002290 *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
ths6f430242007-08-25 01:39:57 +00002291
2292 strcpy(*cred, certdir);
2293 strcat(*cred, "/");
2294 strcat(*cred, filename);
2295
2296 VNC_DEBUG("Check %s\n", *cred);
2297 if (stat(*cred, &sb) < 0) {
2298 qemu_free(*cred);
2299 *cred = NULL;
2300 if (ignoreMissing && errno == ENOENT)
2301 return 0;
2302 return -1;
2303 }
2304
2305 return 0;
2306}
2307
2308static int vnc_set_x509_credential_dir(VncState *vs,
2309 const char *certdir)
2310{
2311 if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
2312 goto cleanup;
2313 if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0)
2314 goto cleanup;
2315 if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0)
2316 goto cleanup;
2317 if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0)
2318 goto cleanup;
2319
2320 return 0;
2321
2322 cleanup:
2323 qemu_free(vs->x509cacert);
2324 qemu_free(vs->x509cacrl);
2325 qemu_free(vs->x509cert);
2326 qemu_free(vs->x509key);
2327 vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL;
2328 return -1;
2329}
2330#endif /* CONFIG_VNC_TLS */
2331
ths71cab5c2007-08-25 01:35:38 +00002332void vnc_display_close(DisplayState *ds)
2333{
thse25a5822007-08-25 01:36:20 +00002334 VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
ths71cab5c2007-08-25 01:35:38 +00002335
aliguori452b4d82009-02-11 21:00:38 +00002336 if (!vs)
2337 return;
ths71cab5c2007-08-25 01:35:38 +00002338 if (vs->display) {
2339 qemu_free(vs->display);
2340 vs->display = NULL;
2341 }
2342 if (vs->lsock != -1) {
2343 qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
2344 close(vs->lsock);
2345 vs->lsock = -1;
2346 }
2347 if (vs->csock != -1) {
2348 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
2349 closesocket(vs->csock);
2350 vs->csock = -1;
2351 buffer_reset(&vs->input);
2352 buffer_reset(&vs->output);
2353 vs->need_update = 0;
blueswir1eb38c522008-09-06 17:47:39 +00002354#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002355 if (vs->tls_session) {
2356 gnutls_deinit(vs->tls_session);
2357 vs->tls_session = NULL;
2358 }
2359 vs->wiremode = VNC_WIREMODE_CLEAR;
2360#endif /* CONFIG_VNC_TLS */
ths71cab5c2007-08-25 01:35:38 +00002361 }
ths70848512007-08-25 01:37:05 +00002362 vs->auth = VNC_AUTH_INVALID;
blueswir1eb38c522008-09-06 17:47:39 +00002363#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002364 vs->subauth = VNC_AUTH_INVALID;
ths469b15c2007-08-25 01:39:10 +00002365 vs->x509verify = 0;
ths8d5d2d42007-08-25 01:37:51 +00002366#endif
malc429a8ed2008-12-01 20:57:48 +00002367 audio_del(vs);
ths71cab5c2007-08-25 01:35:38 +00002368}
2369
ths70848512007-08-25 01:37:05 +00002370int vnc_display_password(DisplayState *ds, const char *password)
2371{
2372 VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
2373
2374 if (vs->password) {
2375 qemu_free(vs->password);
2376 vs->password = NULL;
2377 }
2378 if (password && password[0]) {
2379 if (!(vs->password = qemu_strdup(password)))
2380 return -1;
2381 }
2382
2383 return 0;
2384}
2385
2386int vnc_display_open(DisplayState *ds, const char *display)
ths71cab5c2007-08-25 01:35:38 +00002387{
thse25a5822007-08-25 01:36:20 +00002388 VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
ths70848512007-08-25 01:37:05 +00002389 const char *options;
2390 int password = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002391 int reverse = 0;
aliguori9712eca2008-11-11 20:51:59 +00002392 int to_port = 0;
blueswir1eb38c522008-09-06 17:47:39 +00002393#ifdef CONFIG_VNC_TLS
ths3a702692007-08-25 01:38:36 +00002394 int tls = 0, x509 = 0;
ths8d5d2d42007-08-25 01:37:51 +00002395#endif
ths71cab5c2007-08-25 01:35:38 +00002396
aliguori452b4d82009-02-11 21:00:38 +00002397 if (!vnc_state)
2398 return -1;
ths71cab5c2007-08-25 01:35:38 +00002399 vnc_display_close(ds);
ths70848512007-08-25 01:37:05 +00002400 if (strcmp(display, "none") == 0)
ths71cab5c2007-08-25 01:35:38 +00002401 return 0;
2402
ths70848512007-08-25 01:37:05 +00002403 if (!(vs->display = strdup(display)))
ths71cab5c2007-08-25 01:35:38 +00002404 return -1;
ths70848512007-08-25 01:37:05 +00002405
2406 options = display;
2407 while ((options = strchr(options, ','))) {
2408 options++;
ths469b15c2007-08-25 01:39:10 +00002409 if (strncmp(options, "password", 8) == 0) {
ths70848512007-08-25 01:37:05 +00002410 password = 1; /* Require password auth */
balrog3aa3eea2008-02-03 02:54:04 +00002411 } else if (strncmp(options, "reverse", 7) == 0) {
2412 reverse = 1;
aliguori9712eca2008-11-11 20:51:59 +00002413 } else if (strncmp(options, "to=", 3) == 0) {
2414 to_port = atoi(options+3) + 5900;
blueswir1eb38c522008-09-06 17:47:39 +00002415#ifdef CONFIG_VNC_TLS
ths469b15c2007-08-25 01:39:10 +00002416 } else if (strncmp(options, "tls", 3) == 0) {
ths8d5d2d42007-08-25 01:37:51 +00002417 tls = 1; /* Require TLS */
ths469b15c2007-08-25 01:39:10 +00002418 } else if (strncmp(options, "x509", 4) == 0) {
ths6f430242007-08-25 01:39:57 +00002419 char *start, *end;
ths3a702692007-08-25 01:38:36 +00002420 x509 = 1; /* Require x509 certificates */
ths6f430242007-08-25 01:39:57 +00002421 if (strncmp(options, "x509verify", 10) == 0)
2422 vs->x509verify = 1; /* ...and verify client certs */
2423
2424 /* Now check for 'x509=/some/path' postfix
2425 * and use that to setup x509 certificate/key paths */
2426 start = strchr(options, '=');
2427 end = strchr(options, ',');
2428 if (start && (!end || (start < end))) {
2429 int len = end ? end-(start+1) : strlen(start+1);
balrogbe351262008-11-12 16:50:36 +00002430 char *path = qemu_strndup(start + 1, len);
blueswir1be15b142008-10-25 11:21:28 +00002431
ths6f430242007-08-25 01:39:57 +00002432 VNC_DEBUG("Trying certificate path '%s'\n", path);
2433 if (vnc_set_x509_credential_dir(vs, path) < 0) {
2434 fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
2435 qemu_free(path);
2436 qemu_free(vs->display);
2437 vs->display = NULL;
2438 return -1;
2439 }
2440 qemu_free(path);
2441 } else {
2442 fprintf(stderr, "No certificate path provided\n");
2443 qemu_free(vs->display);
2444 vs->display = NULL;
2445 return -1;
2446 }
ths8d5d2d42007-08-25 01:37:51 +00002447#endif
ths469b15c2007-08-25 01:39:10 +00002448 }
ths70848512007-08-25 01:37:05 +00002449 }
2450
2451 if (password) {
blueswir1eb38c522008-09-06 17:47:39 +00002452#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002453 if (tls) {
ths8d5d2d42007-08-25 01:37:51 +00002454 vs->auth = VNC_AUTH_VENCRYPT;
ths3a702692007-08-25 01:38:36 +00002455 if (x509) {
2456 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
2457 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
2458 } else {
2459 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
2460 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
2461 }
ths8d5d2d42007-08-25 01:37:51 +00002462 } else {
2463#endif
2464 VNC_DEBUG("Initializing VNC server with password auth\n");
2465 vs->auth = VNC_AUTH_VNC;
blueswir1eb38c522008-09-06 17:47:39 +00002466#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002467 vs->subauth = VNC_AUTH_INVALID;
2468 }
2469#endif
ths70848512007-08-25 01:37:05 +00002470 } else {
blueswir1eb38c522008-09-06 17:47:39 +00002471#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002472 if (tls) {
ths8d5d2d42007-08-25 01:37:51 +00002473 vs->auth = VNC_AUTH_VENCRYPT;
ths3a702692007-08-25 01:38:36 +00002474 if (x509) {
2475 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
2476 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
2477 } else {
2478 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
2479 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
2480 }
ths8d5d2d42007-08-25 01:37:51 +00002481 } else {
2482#endif
2483 VNC_DEBUG("Initializing VNC server with no auth\n");
2484 vs->auth = VNC_AUTH_NONE;
blueswir1eb38c522008-09-06 17:47:39 +00002485#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002486 vs->subauth = VNC_AUTH_INVALID;
2487 }
2488#endif
ths70848512007-08-25 01:37:05 +00002489 }
bellard24236862006-04-30 21:28:36 +00002490
balrog3aa3eea2008-02-03 02:54:04 +00002491 if (reverse) {
aliguori9712eca2008-11-11 20:51:59 +00002492 /* connect to viewer */
2493 if (strncmp(display, "unix:", 5) == 0)
2494 vs->lsock = unix_connect(display+5);
2495 else
2496 vs->lsock = inet_connect(display, SOCK_STREAM);
2497 if (-1 == vs->lsock) {
balrog3aa3eea2008-02-03 02:54:04 +00002498 free(vs->display);
2499 vs->display = NULL;
2500 return -1;
2501 } else {
2502 vs->csock = vs->lsock;
2503 vs->lsock = -1;
2504 vnc_connect(vs);
balrog3aa3eea2008-02-03 02:54:04 +00002505 }
aliguori9712eca2008-11-11 20:51:59 +00002506 return 0;
balrog3aa3eea2008-02-03 02:54:04 +00002507
aliguori9712eca2008-11-11 20:51:59 +00002508 } else {
2509 /* listen for connects */
2510 char *dpy;
2511 dpy = qemu_malloc(256);
2512 if (strncmp(display, "unix:", 5) == 0) {
blueswir1bc575e92009-01-14 18:34:22 +00002513 pstrcpy(dpy, 256, "unix:");
aliguori4a55bfd2008-12-02 20:02:14 +00002514 vs->lsock = unix_listen(display+5, dpy+5, 256-5);
aliguori9712eca2008-11-11 20:51:59 +00002515 } else {
2516 vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
2517 }
2518 if (-1 == vs->lsock) {
2519 free(dpy);
balrogd0513622008-12-01 01:48:36 +00002520 return -1;
aliguori9712eca2008-11-11 20:51:59 +00002521 } else {
2522 free(vs->display);
2523 vs->display = dpy;
2524 }
bellard24236862006-04-30 21:28:36 +00002525 }
2526
ths71cab5c2007-08-25 01:35:38 +00002527 return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00002528}