blob: c54c6e070cc82093bc5f8a55fbfaba086f73a511 [file] [log] [blame]
bellard7d510b82006-05-01 10:38:19 +00001/*
2 * QEMU VNC display driver
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard7d510b82006-05-01 10:38:19 +00004 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5 * Copyright (C) 2006 Fabrice Bellard
aliguori19a490b2009-03-06 20:27:13 +00006 * Copyright (C) 2009 Red Hat, Inc
ths5fafdf22007-09-16 21:08:06 +00007 *
bellard7d510b82006-05-01 10:38:19 +00008 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
aliguori19a490b2009-03-06 20:27:13 +000027#include "vnc.h"
pbrook87ecb682007-11-17 17:14:51 +000028#include "sysemu.h"
bellard6ca957f2006-04-30 22:53:25 +000029#include "qemu_socket.h"
pbrook87ecb682007-11-17 17:14:51 +000030#include "qemu-timer.h"
aliguori76655d62009-03-06 20:27:37 +000031#include "acl.h"
Luiz Capitulinod96fd292009-12-10 17:16:10 -020032#include "qemu-objects.h"
bellard24236862006-04-30 21:28:36 +000033
Stefano Stabellini2430ffe2009-08-03 10:56:01 +010034#define VNC_REFRESH_INTERVAL_BASE 30
35#define VNC_REFRESH_INTERVAL_INC 50
36#define VNC_REFRESH_INTERVAL_MAX 2000
bellard24236862006-04-30 21:28:36 +000037
38#include "vnc_keysym.h"
ths70848512007-08-25 01:37:05 +000039#include "d3des.h"
40
aliguori90a1e3c2009-01-26 15:37:30 +000041#define count_bits(c, v) { \
42 for (c = 0; v; v >>= 1) \
43 { \
44 c += v & 1; \
45 } \
46}
ths8d5d2d42007-08-25 01:37:51 +000047
bellard24236862006-04-30 21:28:36 +000048
aliguori753b4052009-02-16 14:59:30 +000049static VncDisplay *vnc_display; /* needed for info vnc */
aliguori7d957bd2009-01-15 22:14:11 +000050static DisplayChangeListener *dcl;
bellarda9ce8592007-02-05 20:20:30 +000051
aliguori1ff7df12009-03-06 20:27:05 +000052static char *addr_to_string(const char *format,
53 struct sockaddr_storage *sa,
54 socklen_t salen) {
55 char *addr;
56 char host[NI_MAXHOST];
57 char serv[NI_MAXSERV];
58 int err;
aliguori457772e2009-03-13 15:03:27 +000059 size_t addrlen;
aliguori1ff7df12009-03-06 20:27:05 +000060
61 if ((err = getnameinfo((struct sockaddr *)sa, salen,
62 host, sizeof(host),
63 serv, sizeof(serv),
64 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
65 VNC_DEBUG("Cannot resolve address %d: %s\n",
66 err, gai_strerror(err));
67 return NULL;
68 }
69
aliguori457772e2009-03-13 15:03:27 +000070 /* Enough for the existing format + the 2 vars we're
Stefan Weilf425c272009-06-06 17:00:31 +020071 * substituting in. */
aliguori457772e2009-03-13 15:03:27 +000072 addrlen = strlen(format) + strlen(host) + strlen(serv);
73 addr = qemu_malloc(addrlen + 1);
74 snprintf(addr, addrlen, format, host, serv);
75 addr[addrlen] = '\0';
aliguori1ff7df12009-03-06 20:27:05 +000076
77 return addr;
78}
79
aliguori2f9606b2009-03-06 20:27:28 +000080
81char *vnc_socket_local_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +000082 struct sockaddr_storage sa;
83 socklen_t salen;
84
85 salen = sizeof(sa);
86 if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
87 return NULL;
88
89 return addr_to_string(format, &sa, salen);
90}
91
aliguori2f9606b2009-03-06 20:27:28 +000092char *vnc_socket_remote_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +000093 struct sockaddr_storage sa;
94 socklen_t salen;
95
96 salen = sizeof(sa);
97 if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
98 return NULL;
99
100 return addr_to_string(format, &sa, salen);
101}
102
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200103static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa,
104 socklen_t salen)
105{
106 char host[NI_MAXHOST];
107 char serv[NI_MAXSERV];
108 int err;
109
110 if ((err = getnameinfo((struct sockaddr *)sa, salen,
111 host, sizeof(host),
112 serv, sizeof(serv),
113 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
114 VNC_DEBUG("Cannot resolve address %d: %s\n",
115 err, gai_strerror(err));
116 return -1;
117 }
118
119 qdict_put(qdict, "host", qstring_from_str(host));
120 qdict_put(qdict, "service", qstring_from_str(serv));
121
122 return 0;
123}
124
125static int vnc_qdict_local_addr(QDict *qdict, int fd)
126{
127 struct sockaddr_storage sa;
128 socklen_t salen;
129
130 salen = sizeof(sa);
131 if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
132 return -1;
133 }
134
135 return put_addr_qdict(qdict, &sa, salen);
136}
137
138static int vnc_qdict_remote_addr(QDict *qdict, int fd)
139{
140 struct sockaddr_storage sa;
141 socklen_t salen;
142
143 salen = sizeof(sa);
144 if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
145 return -1;
146 }
147
148 return put_addr_qdict(qdict, &sa, salen);
149}
150
aliguori1ff7df12009-03-06 20:27:05 +0000151static const char *vnc_auth_name(VncDisplay *vd) {
152 switch (vd->auth) {
153 case VNC_AUTH_INVALID:
154 return "invalid";
155 case VNC_AUTH_NONE:
156 return "none";
157 case VNC_AUTH_VNC:
158 return "vnc";
159 case VNC_AUTH_RA2:
160 return "ra2";
161 case VNC_AUTH_RA2NE:
162 return "ra2ne";
163 case VNC_AUTH_TIGHT:
164 return "tight";
165 case VNC_AUTH_ULTRA:
166 return "ultra";
167 case VNC_AUTH_TLS:
168 return "tls";
169 case VNC_AUTH_VENCRYPT:
170#ifdef CONFIG_VNC_TLS
171 switch (vd->subauth) {
172 case VNC_AUTH_VENCRYPT_PLAIN:
173 return "vencrypt+plain";
174 case VNC_AUTH_VENCRYPT_TLSNONE:
175 return "vencrypt+tls+none";
176 case VNC_AUTH_VENCRYPT_TLSVNC:
177 return "vencrypt+tls+vnc";
178 case VNC_AUTH_VENCRYPT_TLSPLAIN:
179 return "vencrypt+tls+plain";
180 case VNC_AUTH_VENCRYPT_X509NONE:
181 return "vencrypt+x509+none";
182 case VNC_AUTH_VENCRYPT_X509VNC:
183 return "vencrypt+x509+vnc";
184 case VNC_AUTH_VENCRYPT_X509PLAIN:
185 return "vencrypt+x509+plain";
aliguori28a76be2009-03-06 20:27:40 +0000186 case VNC_AUTH_VENCRYPT_TLSSASL:
187 return "vencrypt+tls+sasl";
188 case VNC_AUTH_VENCRYPT_X509SASL:
189 return "vencrypt+x509+sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000190 default:
191 return "vencrypt";
192 }
193#else
194 return "vencrypt";
195#endif
aliguori2f9606b2009-03-06 20:27:28 +0000196 case VNC_AUTH_SASL:
aliguori28a76be2009-03-06 20:27:40 +0000197 return "sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000198 }
199 return "unknown";
200}
201
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200202static QDict *do_info_vnc_client(Monitor *mon, VncState *client)
aliguori1ff7df12009-03-06 20:27:05 +0000203{
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200204 QDict *qdict;
aliguori1ff7df12009-03-06 20:27:05 +0000205
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200206 qdict = qdict_new();
207 if (vnc_qdict_remote_addr(qdict, client->csock) < 0) {
208 QDECREF(qdict);
209 return NULL;
210 }
aliguori1263b7d2009-03-06 20:27:32 +0000211
212#ifdef CONFIG_VNC_TLS
213 if (client->tls.session &&
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200214 client->tls.dname) {
215 qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname));
216 }
aliguori1263b7d2009-03-06 20:27:32 +0000217#endif
218#ifdef CONFIG_VNC_SASL
219 if (client->sasl.conn &&
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200220 client->sasl.username) {
221 qdict_put(qdict, "username", qstring_from_str(client->sasl.username));
222 }
223#endif
224
225 return qdict;
226}
227
228static void info_vnc_iter(QObject *obj, void *opaque)
229{
230 QDict *client;
231 Monitor *mon = opaque;
232
233 client = qobject_to_qdict(obj);
234 monitor_printf(mon, "Client:\n");
235 monitor_printf(mon, " address: %s:%s\n",
236 qdict_get_str(client, "host"),
237 qdict_get_str(client, "service"));
238
239#ifdef CONFIG_VNC_TLS
240 monitor_printf(mon, " x509_dname: %s\n",
241 qdict_haskey(client, "x509_dname") ?
242 qdict_get_str(client, "x509_dname") : "none");
243#endif
244#ifdef CONFIG_VNC_SASL
245 monitor_printf(mon, " username: %s\n",
246 qdict_haskey(client, "username") ?
247 qdict_get_str(client, "username") : "none");
aliguori1263b7d2009-03-06 20:27:32 +0000248#endif
aliguori1ff7df12009-03-06 20:27:05 +0000249}
250
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200251void do_info_vnc_print(Monitor *mon, const QObject *data)
252{
253 QDict *server;
254 QList *clients;
255
256 server = qobject_to_qdict(data);
257 if (strcmp(qdict_get_str(server, "status"), "disabled") == 0) {
258 monitor_printf(mon, "Server: disabled\n");
259 return;
260 }
261
262 monitor_printf(mon, "Server:\n");
263 monitor_printf(mon, " address: %s:%s\n",
264 qdict_get_str(server, "host"),
265 qdict_get_str(server, "service"));
266 monitor_printf(mon, " auth: %s\n",
267 qdict_haskey(server, "auth") ? qdict_get_str(server, "auth") : "none");
268
269 clients = qdict_get_qlist(server, "clients");
270 if (qlist_empty(clients)) {
271 monitor_printf(mon, "Client: none\n");
272 } else {
273 qlist_iter(clients, info_vnc_iter, mon);
274 }
275}
276
277/**
278 * do_info_vnc(): Show VNC server information
279 *
280 * Return a QDict with server information. Connected clients are returned
281 * as a QList of QDicts.
282 *
283 * The main QDict contains the following:
284 *
285 * - "status": "disabled" or "enabled"
286 * - "host": server's IP address
287 * - "service": server's port number
288 * - "auth": authentication method (optional)
289 * - "clients": a QList of all connected clients
290 *
291 * Clients are described by a QDict, with the following information:
292 *
293 * - "host": client's IP address
294 * - "service": client's port number
295 * - "x509_dname": TLS dname (optional)
296 * - "username": SASL username (optional)
297 *
298 * Example:
299 *
300 * { "status": "enabled", "host": "0.0.0.0", "service": "50402", "auth": "vnc",
301 * "clients": [ { "host": "127.0.0.1", "service": "50401" } ] }
302 */
303void do_info_vnc(Monitor *mon, QObject **ret_data)
bellarda9ce8592007-02-05 20:20:30 +0000304{
aliguori1ff7df12009-03-06 20:27:05 +0000305 if (vnc_display == NULL || vnc_display->display == NULL) {
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200306 *ret_data = qobject_from_jsonf("{ 'status': 'disabled' }");
aliguori1ff7df12009-03-06 20:27:05 +0000307 } else {
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200308 QDict *qdict;
309 QList *clist;
bellarda9ce8592007-02-05 20:20:30 +0000310
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200311 clist = qlist_new();
aliguori1ff7df12009-03-06 20:27:05 +0000312 if (vnc_display->clients) {
313 VncState *client = vnc_display->clients;
314 while (client) {
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200315 qdict = do_info_vnc_client(mon, client);
316 if (qdict)
317 qlist_append(clist, qdict);
aliguori1ff7df12009-03-06 20:27:05 +0000318 client = client->next;
319 }
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200320 }
321
322 *ret_data = qobject_from_jsonf("{ 'status': 'enabled', 'clients': %p }",
323 QOBJECT(clist));
324 assert(*ret_data != NULL);
325
326 qdict = qobject_to_qdict(*ret_data);
327
328 if (vnc_display->auth != VNC_AUTH_NONE) {
329 qdict_put(qdict, "auth",
330 qstring_from_str(vnc_auth_name(vnc_display)));
331 }
332
333 if (vnc_qdict_local_addr(qdict, vnc_display->lsock) < 0) {
334 qobject_decref(*ret_data);
335 *ret_data = NULL;
aliguori1ff7df12009-03-06 20:27:05 +0000336 }
bellarda9ce8592007-02-05 20:20:30 +0000337 }
338}
339
aliguori29fa4ed2009-02-02 15:58:29 +0000340static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
341 return (vs->features & (1 << feature));
342}
343
bellard24236862006-04-30 21:28:36 +0000344/* TODO
345 1) Get the queue working for IO.
346 2) there is some weirdness when using the -S option (the screen is grey
347 and not totally invalidated
348 3) resolutions > 1024
349*/
350
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100351static int vnc_update_client(VncState *vs, int has_dirty);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200352static void vnc_disconnect_start(VncState *vs);
353static void vnc_disconnect_finish(VncState *vs);
Stefano Stabellini703bc682009-08-03 10:54:05 +0100354static void vnc_init_timer(VncDisplay *vd);
355static void vnc_remove_timer(VncDisplay *vd);
bellard24236862006-04-30 21:28:36 +0000356
aliguori753b4052009-02-16 14:59:30 +0000357static void vnc_colordepth(VncState *vs);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100358static void framebuffer_update_request(VncState *vs, int incremental,
359 int x_position, int y_position,
360 int w, int h);
361static void vnc_refresh(void *opaque);
362static int vnc_refresh_server_surface(VncDisplay *vd);
aliguori7eac3a82008-09-15 16:03:41 +0000363
bellard99589bd2006-06-13 16:35:24 +0000364static inline void vnc_set_bit(uint32_t *d, int k)
365{
366 d[k >> 5] |= 1 << (k & 0x1f);
367}
368
369static inline void vnc_clear_bit(uint32_t *d, int k)
370{
371 d[k >> 5] &= ~(1 << (k & 0x1f));
372}
373
374static inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
375{
376 int j;
377
378 j = 0;
379 while (n >= 32) {
380 d[j++] = -1;
381 n -= 32;
382 }
ths5fafdf22007-09-16 21:08:06 +0000383 if (n > 0)
bellard99589bd2006-06-13 16:35:24 +0000384 d[j++] = (1 << n) - 1;
385 while (j < nb_words)
386 d[j++] = 0;
387}
388
389static inline int vnc_get_bit(const uint32_t *d, int k)
390{
391 return (d[k >> 5] >> (k & 0x1f)) & 1;
392}
393
ths5fafdf22007-09-16 21:08:06 +0000394static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
bellard99589bd2006-06-13 16:35:24 +0000395 int nb_words)
396{
397 int i;
398 for(i = 0; i < nb_words; i++) {
399 if ((d1[i] & d2[i]) != 0)
400 return 1;
401 }
402 return 0;
403}
404
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100405static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000406{
bellard24236862006-04-30 21:28:36 +0000407 int i;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100408 VncDisplay *vd = ds->opaque;
409 struct VncSurface *s = &vd->guest;
bellard24236862006-04-30 21:28:36 +0000410
411 h += y;
412
balrog0486e8a2007-12-11 22:31:32 +0000413 /* round x down to ensure the loop only spans one 16-pixel block per,
414 iteration. otherwise, if (x % 16) != 0, the last iteration may span
415 two 16-pixel blocks but we only mark the first as dirty
416 */
417 w += (x % 16);
418 x -= (x % 16);
419
aliguori6baebed2009-03-20 15:59:14 +0000420 x = MIN(x, s->ds->width);
421 y = MIN(y, s->ds->height);
422 w = MIN(x + w, s->ds->width) - x;
423 h = MIN(h, s->ds->height);
balrog788abf82008-05-20 00:07:58 +0000424
bellard24236862006-04-30 21:28:36 +0000425 for (; y < h; y++)
aliguori28a76be2009-03-06 20:27:40 +0000426 for (i = 0; i < w; i += 16)
aliguori6baebed2009-03-20 15:59:14 +0000427 vnc_set_bit(s->dirty[y], (x + i) / 16);
bellard24236862006-04-30 21:28:36 +0000428}
429
430static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
aliguori28a76be2009-03-06 20:27:40 +0000431 int32_t encoding)
bellard24236862006-04-30 21:28:36 +0000432{
433 vnc_write_u16(vs, x);
434 vnc_write_u16(vs, y);
435 vnc_write_u16(vs, w);
436 vnc_write_u16(vs, h);
437
438 vnc_write_s32(vs, encoding);
439}
440
aliguori2f9606b2009-03-06 20:27:28 +0000441void buffer_reserve(Buffer *buffer, size_t len)
aliguori89064282009-02-02 15:58:47 +0000442{
443 if ((buffer->capacity - buffer->offset) < len) {
aliguori28a76be2009-03-06 20:27:40 +0000444 buffer->capacity += (len + 1024);
445 buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
446 if (buffer->buffer == NULL) {
447 fprintf(stderr, "vnc: out of memory\n");
448 exit(1);
449 }
aliguori89064282009-02-02 15:58:47 +0000450 }
451}
452
aliguori2f9606b2009-03-06 20:27:28 +0000453int buffer_empty(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000454{
455 return buffer->offset == 0;
456}
457
aliguori2f9606b2009-03-06 20:27:28 +0000458uint8_t *buffer_end(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000459{
460 return buffer->buffer + buffer->offset;
461}
462
aliguori2f9606b2009-03-06 20:27:28 +0000463void buffer_reset(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000464{
aliguori28a76be2009-03-06 20:27:40 +0000465 buffer->offset = 0;
aliguori89064282009-02-02 15:58:47 +0000466}
467
aliguori2f9606b2009-03-06 20:27:28 +0000468void buffer_append(Buffer *buffer, const void *data, size_t len)
aliguori89064282009-02-02 15:58:47 +0000469{
470 memcpy(buffer->buffer + buffer->offset, data, len);
471 buffer->offset += len;
472}
473
aliguori753b4052009-02-16 14:59:30 +0000474static void vnc_dpy_resize(DisplayState *ds)
475{
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100476 int size_changed;
aliguori753b4052009-02-16 14:59:30 +0000477 VncDisplay *vd = ds->opaque;
478 VncState *vs = vd->clients;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100479
480 /* server surface */
481 if (!vd->server)
482 vd->server = qemu_mallocz(sizeof(*vd->server));
483 if (vd->server->data)
484 qemu_free(vd->server->data);
485 *(vd->server) = *(ds->surface);
486 vd->server->data = qemu_mallocz(vd->server->linesize *
487 vd->server->height);
488
489 /* guest surface */
490 if (!vd->guest.ds)
491 vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
492 if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
493 console_color_init(ds);
494 size_changed = ds_get_width(ds) != vd->guest.ds->width ||
495 ds_get_height(ds) != vd->guest.ds->height;
496 *(vd->guest.ds) = *(ds->surface);
497 memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
498
aliguori753b4052009-02-16 14:59:30 +0000499 while (vs != NULL) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100500 vnc_colordepth(vs);
501 if (size_changed) {
502 if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
503 vnc_write_u8(vs, 0); /* msg id */
504 vnc_write_u8(vs, 0);
505 vnc_write_u16(vs, 1); /* number of rects */
506 vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
507 VNC_ENCODING_DESKTOPRESIZE);
508 vnc_flush(vs);
509 }
510 }
511 memset(vs->dirty, 0xFF, sizeof(vs->dirty));
aliguori753b4052009-02-16 14:59:30 +0000512 vs = vs->next;
513 }
514}
515
bellard35127792006-05-14 18:11:49 +0000516/* fastest code */
517static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
518{
519 vnc_write(vs, pixels, size);
520}
521
522/* slowest but generic code. */
523static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
524{
aliguori7eac3a82008-09-15 16:03:41 +0000525 uint8_t r, g, b;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100526 VncDisplay *vd = vs->vd;
bellard35127792006-05-14 18:11:49 +0000527
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100528 r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >>
529 vd->server->pf.rbits);
530 g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >>
531 vd->server->pf.gbits);
532 b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >>
533 vd->server->pf.bbits);
aliguori6cec5482009-01-15 22:17:38 +0000534 v = (r << vs->clientds.pf.rshift) |
535 (g << vs->clientds.pf.gshift) |
536 (b << vs->clientds.pf.bshift);
537 switch(vs->clientds.pf.bytes_per_pixel) {
bellard35127792006-05-14 18:11:49 +0000538 case 1:
539 buf[0] = v;
540 break;
541 case 2:
aliguori6cec5482009-01-15 22:17:38 +0000542 if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
bellard35127792006-05-14 18:11:49 +0000543 buf[0] = v >> 8;
544 buf[1] = v;
545 } else {
546 buf[1] = v >> 8;
547 buf[0] = v;
548 }
549 break;
550 default:
551 case 4:
aliguori6cec5482009-01-15 22:17:38 +0000552 if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
bellard35127792006-05-14 18:11:49 +0000553 buf[0] = v >> 24;
554 buf[1] = v >> 16;
555 buf[2] = v >> 8;
556 buf[3] = v;
557 } else {
558 buf[3] = v >> 24;
559 buf[2] = v >> 16;
560 buf[1] = v >> 8;
561 buf[0] = v;
562 }
563 break;
564 }
565}
566
567static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
568{
bellard35127792006-05-14 18:11:49 +0000569 uint8_t buf[4];
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100570 VncDisplay *vd = vs->vd;
bellard35127792006-05-14 18:11:49 +0000571
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100572 if (vd->server->pf.bytes_per_pixel == 4) {
aliguori7eac3a82008-09-15 16:03:41 +0000573 uint32_t *pixels = pixels1;
574 int n, i;
575 n = size >> 2;
576 for(i = 0; i < n; i++) {
577 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000578 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000579 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100580 } else if (vd->server->pf.bytes_per_pixel == 2) {
aliguori7eac3a82008-09-15 16:03:41 +0000581 uint16_t *pixels = pixels1;
582 int n, i;
583 n = size >> 1;
584 for(i = 0; i < n; i++) {
585 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000586 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000587 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100588 } else if (vd->server->pf.bytes_per_pixel == 1) {
aliguori7eac3a82008-09-15 16:03:41 +0000589 uint8_t *pixels = pixels1;
590 int n, i;
591 n = size;
592 for(i = 0; i < n; i++) {
593 vnc_convert_pixel(vs, buf, pixels[i]);
aliguori6cec5482009-01-15 22:17:38 +0000594 vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000595 }
596 } else {
597 fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
bellard35127792006-05-14 18:11:49 +0000598 }
599}
600
bellard24236862006-04-30 21:28:36 +0000601static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
602{
603 int i;
ths60fe76f2007-12-16 03:02:09 +0000604 uint8_t *row;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100605 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000606
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100607 row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
bellard24236862006-04-30 21:28:36 +0000608 for (i = 0; i < h; i++) {
aliguori28a76be2009-03-06 20:27:40 +0000609 vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
610 row += ds_get_linesize(vs->ds);
bellard24236862006-04-30 21:28:36 +0000611 }
612}
613
614static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
615{
616 ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
617 ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
618}
619
620#define BPP 8
621#include "vnchextile.h"
622#undef BPP
623
624#define BPP 16
625#include "vnchextile.h"
626#undef BPP
627
628#define BPP 32
629#include "vnchextile.h"
630#undef BPP
631
bellard35127792006-05-14 18:11:49 +0000632#define GENERIC
aliguori7eac3a82008-09-15 16:03:41 +0000633#define BPP 8
634#include "vnchextile.h"
635#undef BPP
636#undef GENERIC
637
638#define GENERIC
639#define BPP 16
640#include "vnchextile.h"
641#undef BPP
642#undef GENERIC
643
644#define GENERIC
bellard35127792006-05-14 18:11:49 +0000645#define BPP 32
646#include "vnchextile.h"
647#undef BPP
648#undef GENERIC
649
bellard24236862006-04-30 21:28:36 +0000650static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
651{
652 int i, j;
653 int has_fg, has_bg;
aliguori7eac3a82008-09-15 16:03:41 +0000654 uint8_t *last_fg, *last_bg;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100655 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000656
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100657 last_fg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
658 last_bg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
bellard24236862006-04-30 21:28:36 +0000659 has_fg = has_bg = 0;
660 for (j = y; j < (y + h); j += 16) {
aliguori28a76be2009-03-06 20:27:40 +0000661 for (i = x; i < (x + w); i += 16) {
ths5fafdf22007-09-16 21:08:06 +0000662 vs->send_hextile_tile(vs, i, j,
bellard35127792006-05-14 18:11:49 +0000663 MIN(16, x + w - i), MIN(16, y + h - j),
aliguori7eac3a82008-09-15 16:03:41 +0000664 last_bg, last_fg, &has_bg, &has_fg);
aliguori28a76be2009-03-06 20:27:40 +0000665 }
bellard24236862006-04-30 21:28:36 +0000666 }
aliguori7eac3a82008-09-15 16:03:41 +0000667 free(last_fg);
668 free(last_bg);
669
bellard24236862006-04-30 21:28:36 +0000670}
671
Stefan Weil6c098402009-10-01 20:53:12 +0200672#define ZALLOC_ALIGNMENT 16
673
674static void *zalloc(void *x, unsigned items, unsigned size)
675{
676 void *p;
677
678 size *= items;
679 size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
680
681 p = qemu_mallocz(size);
682
683 return (p);
684}
685
686static void zfree(void *x, void *addr)
687{
688 qemu_free(addr);
689}
690
aliguori059cef42009-02-02 15:58:54 +0000691static void vnc_zlib_init(VncState *vs)
692{
693 int i;
694 for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++)
695 vs->zlib_stream[i].opaque = NULL;
696}
697
698static void vnc_zlib_start(VncState *vs)
699{
700 buffer_reset(&vs->zlib);
701
702 // make the output buffer be the zlib buffer, so we can compress it later
703 vs->zlib_tmp = vs->output;
704 vs->output = vs->zlib;
705}
706
707static int vnc_zlib_stop(VncState *vs, int stream_id)
708{
709 z_streamp zstream = &vs->zlib_stream[stream_id];
710 int previous_out;
711
712 // switch back to normal output/zlib buffers
713 vs->zlib = vs->output;
714 vs->output = vs->zlib_tmp;
715
716 // compress the zlib buffer
717
718 // initialize the stream
719 // XXX need one stream per session
720 if (zstream->opaque != vs) {
721 int err;
722
723 VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
724 VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
Stefan Weil6c098402009-10-01 20:53:12 +0200725 zstream->zalloc = zalloc;
726 zstream->zfree = zfree;
aliguori059cef42009-02-02 15:58:54 +0000727
728 err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
729 MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
730
731 if (err != Z_OK) {
732 fprintf(stderr, "VNC: error initializing zlib\n");
733 return -1;
734 }
735
736 zstream->opaque = vs;
737 }
738
739 // XXX what to do if tight_compression changed in between?
740
741 // reserve memory in output buffer
742 buffer_reserve(&vs->output, vs->zlib.offset + 64);
743
744 // set pointers
745 zstream->next_in = vs->zlib.buffer;
746 zstream->avail_in = vs->zlib.offset;
747 zstream->next_out = vs->output.buffer + vs->output.offset;
748 zstream->avail_out = vs->output.capacity - vs->output.offset;
749 zstream->data_type = Z_BINARY;
750 previous_out = zstream->total_out;
751
752 // start encoding
753 if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
754 fprintf(stderr, "VNC: error during zlib compression\n");
755 return -1;
756 }
757
758 vs->output.offset = vs->output.capacity - zstream->avail_out;
759 return zstream->total_out - previous_out;
760}
761
762static void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h)
763{
764 int old_offset, new_offset, bytes_written;
765
766 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
767
768 // remember where we put in the follow-up size
769 old_offset = vs->output.offset;
770 vnc_write_s32(vs, 0);
771
772 // compress the stream
773 vnc_zlib_start(vs);
774 send_framebuffer_update_raw(vs, x, y, w, h);
775 bytes_written = vnc_zlib_stop(vs, 0);
776
777 if (bytes_written == -1)
778 return;
779
780 // hack in the size
781 new_offset = vs->output.offset;
782 vs->output.offset = old_offset;
783 vnc_write_u32(vs, bytes_written);
784 vs->output.offset = new_offset;
785}
786
bellard24236862006-04-30 21:28:36 +0000787static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
788{
aliguorifb437312009-02-02 15:58:43 +0000789 switch(vs->vnc_encoding) {
aliguori28a76be2009-03-06 20:27:40 +0000790 case VNC_ENCODING_ZLIB:
791 send_framebuffer_update_zlib(vs, x, y, w, h);
792 break;
793 case VNC_ENCODING_HEXTILE:
794 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
795 send_framebuffer_update_hextile(vs, x, y, w, h);
796 break;
797 default:
798 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
799 send_framebuffer_update_raw(vs, x, y, w, h);
800 break;
aliguorifb437312009-02-02 15:58:43 +0000801 }
bellard24236862006-04-30 21:28:36 +0000802}
803
aliguori753b4052009-02-16 14:59:30 +0000804static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000805{
Gerd Hoffmann3e28c9a2009-07-27 17:10:48 +0200806 /* send bitblit op to the vnc client */
bellard24236862006-04-30 21:28:36 +0000807 vnc_write_u8(vs, 0); /* msg id */
808 vnc_write_u8(vs, 0);
809 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000810 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
bellard24236862006-04-30 21:28:36 +0000811 vnc_write_u16(vs, src_x);
812 vnc_write_u16(vs, src_y);
813 vnc_flush(vs);
814}
815
aliguori753b4052009-02-16 14:59:30 +0000816static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
817{
818 VncDisplay *vd = ds->opaque;
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200819 VncState *vs, *vn;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100820 uint8_t *src_row;
821 uint8_t *dst_row;
822 int i,x,y,pitch,depth,inc,w_lim,s;
823 int cmp_bytes;
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200824
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100825 vnc_refresh_server_surface(vd);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200826 for (vs = vd->clients; vs != NULL; vs = vn) {
827 vn = vs->next;
828 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
829 vs->force_update = 1;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100830 vnc_update_client(vs, 1);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200831 /* vs might be free()ed here */
832 }
833 }
834
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100835 /* do bitblit op on the local surface too */
836 pitch = ds_get_linesize(vd->ds);
837 depth = ds_get_bytes_per_pixel(vd->ds);
838 src_row = vd->server->data + pitch * src_y + depth * src_x;
839 dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
840 y = dst_y;
841 inc = 1;
842 if (dst_y > src_y) {
843 /* copy backwards */
844 src_row += pitch * (h-1);
845 dst_row += pitch * (h-1);
846 pitch = -pitch;
847 y = dst_y + h - 1;
848 inc = -1;
849 }
850 w_lim = w - (16 - (dst_x % 16));
851 if (w_lim < 0)
852 w_lim = w;
853 else
854 w_lim = w - (w_lim % 16);
855 for (i = 0; i < h; i++) {
856 for (x = 0; x <= w_lim;
857 x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
858 if (x == w_lim) {
859 if ((s = w - w_lim) == 0)
860 break;
861 } else if (!x) {
862 s = (16 - (dst_x % 16));
863 s = MIN(s, w_lim);
864 } else {
865 s = 16;
866 }
867 cmp_bytes = s * depth;
868 if (memcmp(src_row, dst_row, cmp_bytes) == 0)
869 continue;
870 memmove(dst_row, src_row, cmp_bytes);
871 vs = vd->clients;
872 while (vs != NULL) {
873 if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
874 vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16));
875 vs = vs->next;
876 }
877 }
878 src_row += pitch - w * depth;
879 dst_row += pitch - w * depth;
880 y += inc;
881 }
882
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200883 for (vs = vd->clients; vs != NULL; vs = vs->next) {
aliguori753b4052009-02-16 14:59:30 +0000884 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
885 vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
aliguori753b4052009-02-16 14:59:30 +0000886 }
887}
888
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100889static int find_and_clear_dirty_height(struct VncState *vs,
aliguori6baebed2009-03-20 15:59:14 +0000890 int y, int last_x, int x)
bellard24236862006-04-30 21:28:36 +0000891{
892 int h;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100893 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000894
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100895 for (h = 1; h < (vd->server->height - y); h++) {
aliguori28a76be2009-03-06 20:27:40 +0000896 int tmp_x;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100897 if (!vnc_get_bit(vs->dirty[y + h], last_x))
aliguori28a76be2009-03-06 20:27:40 +0000898 break;
899 for (tmp_x = last_x; tmp_x < x; tmp_x++)
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100900 vnc_clear_bit(vs->dirty[y + h], tmp_x);
bellard24236862006-04-30 21:28:36 +0000901 }
902
903 return h;
904}
905
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100906static int vnc_update_client(VncState *vs, int has_dirty)
bellard24236862006-04-30 21:28:36 +0000907{
bellard24236862006-04-30 21:28:36 +0000908 if (vs->need_update && vs->csock != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100909 VncDisplay *vd = vs->vd;
aliguori28a76be2009-03-06 20:27:40 +0000910 int y;
aliguori28a76be2009-03-06 20:27:40 +0000911 int n_rectangles;
912 int saved_offset;
bellard24236862006-04-30 21:28:36 +0000913
Stefano Stabellini703bc682009-08-03 10:54:05 +0100914 if (vs->output.offset && !vs->audio_cap && !vs->force_update)
aliguoric522d0e2009-03-20 15:59:24 +0000915 /* kernel send buffers are full -> drop frames to throttle */
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100916 return 0;
balroga0ecfb72008-01-13 23:51:53 +0000917
Stefano Stabellini703bc682009-08-03 10:54:05 +0100918 if (!has_dirty && !vs->audio_cap && !vs->force_update)
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100919 return 0;
bellard24236862006-04-30 21:28:36 +0000920
aliguori6baebed2009-03-20 15:59:14 +0000921 /*
922 * Send screen updates to the vnc client using the server
923 * surface and server dirty map. guest surface updates
924 * happening in parallel don't disturb us, the next pass will
925 * send them to the client.
926 */
aliguori28a76be2009-03-06 20:27:40 +0000927 n_rectangles = 0;
928 vnc_write_u8(vs, 0); /* msg id */
929 vnc_write_u8(vs, 0);
930 saved_offset = vs->output.offset;
931 vnc_write_u16(vs, 0);
bellard24236862006-04-30 21:28:36 +0000932
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100933 for (y = 0; y < vd->server->height; y++) {
aliguori28a76be2009-03-06 20:27:40 +0000934 int x;
935 int last_x = -1;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100936 for (x = 0; x < vd->server->width / 16; x++) {
937 if (vnc_get_bit(vs->dirty[y], x)) {
aliguori28a76be2009-03-06 20:27:40 +0000938 if (last_x == -1) {
939 last_x = x;
940 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100941 vnc_clear_bit(vs->dirty[y], x);
aliguori28a76be2009-03-06 20:27:40 +0000942 } else {
943 if (last_x != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100944 int h = find_and_clear_dirty_height(vs, y, last_x, x);
aliguori28a76be2009-03-06 20:27:40 +0000945 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
946 n_rectangles++;
947 }
948 last_x = -1;
949 }
950 }
951 if (last_x != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100952 int h = find_and_clear_dirty_height(vs, y, last_x, x);
aliguori28a76be2009-03-06 20:27:40 +0000953 send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
954 n_rectangles++;
955 }
956 }
957 vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
958 vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
959 vnc_flush(vs);
aliguoric522d0e2009-03-20 15:59:24 +0000960 vs->force_update = 0;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100961 return n_rectangles;
bellard24236862006-04-30 21:28:36 +0000962 }
bellard24236862006-04-30 21:28:36 +0000963
Stefano Stabellini703bc682009-08-03 10:54:05 +0100964 if (vs->csock == -1)
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200965 vnc_disconnect_finish(vs);
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100966
967 return 0;
bellard24236862006-04-30 21:28:36 +0000968}
969
malc429a8ed2008-12-01 20:57:48 +0000970/* audio */
971static void audio_capture_notify(void *opaque, audcnotification_e cmd)
972{
973 VncState *vs = opaque;
974
975 switch (cmd) {
976 case AUD_CNOTIFY_DISABLE:
977 vnc_write_u8(vs, 255);
978 vnc_write_u8(vs, 1);
979 vnc_write_u16(vs, 0);
980 vnc_flush(vs);
981 break;
982
983 case AUD_CNOTIFY_ENABLE:
984 vnc_write_u8(vs, 255);
985 vnc_write_u8(vs, 1);
986 vnc_write_u16(vs, 1);
987 vnc_flush(vs);
988 break;
989 }
990}
991
992static void audio_capture_destroy(void *opaque)
993{
994}
995
996static void audio_capture(void *opaque, void *buf, int size)
997{
998 VncState *vs = opaque;
999
1000 vnc_write_u8(vs, 255);
1001 vnc_write_u8(vs, 1);
1002 vnc_write_u16(vs, 2);
1003 vnc_write_u32(vs, size);
1004 vnc_write(vs, buf, size);
1005 vnc_flush(vs);
1006}
1007
1008static void audio_add(VncState *vs)
1009{
aliguori376253e2009-03-05 23:01:23 +00001010 Monitor *mon = cur_mon;
malc429a8ed2008-12-01 20:57:48 +00001011 struct audio_capture_ops ops;
1012
1013 if (vs->audio_cap) {
aliguori376253e2009-03-05 23:01:23 +00001014 monitor_printf(mon, "audio already running\n");
malc429a8ed2008-12-01 20:57:48 +00001015 return;
1016 }
1017
1018 ops.notify = audio_capture_notify;
1019 ops.destroy = audio_capture_destroy;
1020 ops.capture = audio_capture;
1021
malc1a7dafc2009-05-14 03:11:35 +04001022 vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
malc429a8ed2008-12-01 20:57:48 +00001023 if (!vs->audio_cap) {
aliguori376253e2009-03-05 23:01:23 +00001024 monitor_printf(mon, "Failed to add audio capture\n");
malc429a8ed2008-12-01 20:57:48 +00001025 }
1026}
1027
1028static void audio_del(VncState *vs)
1029{
1030 if (vs->audio_cap) {
1031 AUD_del_capture(vs->audio_cap, vs);
1032 vs->audio_cap = NULL;
1033 }
1034}
1035
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001036static void vnc_disconnect_start(VncState *vs)
1037{
1038 if (vs->csock == -1)
1039 return;
1040 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
1041 closesocket(vs->csock);
1042 vs->csock = -1;
1043}
1044
1045static void vnc_disconnect_finish(VncState *vs)
1046{
Stefan Weilfa0cfdf2009-09-19 21:00:09 +02001047 if (vs->input.buffer) {
1048 qemu_free(vs->input.buffer);
1049 vs->input.buffer = NULL;
1050 }
1051 if (vs->output.buffer) {
1052 qemu_free(vs->output.buffer);
1053 vs->output.buffer = NULL;
1054 }
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001055#ifdef CONFIG_VNC_TLS
1056 vnc_tls_client_cleanup(vs);
1057#endif /* CONFIG_VNC_TLS */
1058#ifdef CONFIG_VNC_SASL
1059 vnc_sasl_client_cleanup(vs);
1060#endif /* CONFIG_VNC_SASL */
1061 audio_del(vs);
1062
1063 VncState *p, *parent = NULL;
1064 for (p = vs->vd->clients; p != NULL; p = p->next) {
1065 if (p == vs) {
1066 if (parent)
1067 parent->next = p->next;
1068 else
1069 vs->vd->clients = p->next;
1070 break;
1071 }
1072 parent = p;
1073 }
1074 if (!vs->vd->clients)
1075 dcl->idle = 1;
1076
Stefano Stabellini703bc682009-08-03 10:54:05 +01001077 vnc_remove_timer(vs->vd);
Glauber Costa5d95ac52009-09-25 08:30:57 -04001078 qemu_free(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001079}
aliguori2f9606b2009-03-06 20:27:28 +00001080
1081int vnc_client_io_error(VncState *vs, int ret, int last_errno)
bellard24236862006-04-30 21:28:36 +00001082{
1083 if (ret == 0 || ret == -1) {
balrogea01e5f2008-04-24 23:40:55 +00001084 if (ret == -1) {
1085 switch (last_errno) {
1086 case EINTR:
1087 case EAGAIN:
1088#ifdef _WIN32
1089 case WSAEWOULDBLOCK:
1090#endif
1091 return 0;
1092 default:
1093 break;
1094 }
1095 }
bellard24236862006-04-30 21:28:36 +00001096
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001097 VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
1098 ret, ret < 0 ? last_errno : 0);
1099 vnc_disconnect_start(vs);
aliguori6baebed2009-03-20 15:59:14 +00001100
aliguori28a76be2009-03-06 20:27:40 +00001101 return 0;
bellard24236862006-04-30 21:28:36 +00001102 }
1103 return ret;
1104}
1105
aliguori5fb6c7a2009-03-06 20:27:23 +00001106
1107void vnc_client_error(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001108{
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001109 VNC_DEBUG("Closing down client sock: protocol error\n");
1110 vnc_disconnect_start(vs);
bellard24236862006-04-30 21:28:36 +00001111}
1112
aliguori2f9606b2009-03-06 20:27:28 +00001113
1114/*
1115 * Called to write a chunk of data to the client socket. The data may
1116 * be the raw data, or may have already been encoded by SASL.
1117 * The data will be written either straight onto the socket, or
1118 * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1119 *
1120 * NB, it is theoretically possible to have 2 layers of encryption,
1121 * both SASL, and this TLS layer. It is highly unlikely in practice
1122 * though, since SASL encryption will typically be a no-op if TLS
1123 * is active
1124 *
1125 * Returns the number of bytes written, which may be less than
1126 * the requested 'datalen' if the socket would block. Returns
1127 * -1 on error, and disconnects the client socket.
1128 */
1129long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001130{
bellardceb5caa2006-05-03 21:18:59 +00001131 long ret;
blueswir1eb38c522008-09-06 17:47:39 +00001132#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +00001133 if (vs->tls.session) {
aliguori28a76be2009-03-06 20:27:40 +00001134 ret = gnutls_write(vs->tls.session, data, datalen);
1135 if (ret < 0) {
1136 if (ret == GNUTLS_E_AGAIN)
1137 errno = EAGAIN;
1138 else
1139 errno = EIO;
1140 ret = -1;
1141 }
ths8d5d2d42007-08-25 01:37:51 +00001142 } else
1143#endif /* CONFIG_VNC_TLS */
Stefan Weil70503262009-06-13 13:05:27 +02001144 ret = send(vs->csock, (const void *)data, datalen, 0);
aliguori23decc82009-03-20 15:59:18 +00001145 VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +00001146 return vnc_client_io_error(vs, ret, socket_error());
1147}
1148
1149
1150/*
1151 * Called to write buffered data to the client socket, when not
1152 * using any SASL SSF encryption layers. Will write as much data
1153 * as possible without blocking. If all buffered data is written,
1154 * will switch the FD poll() handler back to read monitoring.
1155 *
1156 * Returns the number of bytes written, which may be less than
1157 * the buffered output data if the socket would block. Returns
1158 * -1 on error, and disconnects the client socket.
1159 */
1160static long vnc_client_write_plain(VncState *vs)
1161{
1162 long ret;
1163
1164#ifdef CONFIG_VNC_SASL
aliguori23decc82009-03-20 15:59:18 +00001165 VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
aliguori2f9606b2009-03-06 20:27:28 +00001166 vs->output.buffer, vs->output.capacity, vs->output.offset,
1167 vs->sasl.waitWriteSSF);
1168
1169 if (vs->sasl.conn &&
1170 vs->sasl.runSSF &&
1171 vs->sasl.waitWriteSSF) {
1172 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
1173 if (ret)
1174 vs->sasl.waitWriteSSF -= ret;
1175 } else
1176#endif /* CONFIG_VNC_SASL */
1177 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
bellard24236862006-04-30 21:28:36 +00001178 if (!ret)
aliguori2f9606b2009-03-06 20:27:28 +00001179 return 0;
bellard24236862006-04-30 21:28:36 +00001180
1181 memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
1182 vs->output.offset -= ret;
1183
1184 if (vs->output.offset == 0) {
aliguori28a76be2009-03-06 20:27:40 +00001185 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00001186 }
aliguori2f9606b2009-03-06 20:27:28 +00001187
1188 return ret;
1189}
1190
1191
1192/*
1193 * First function called whenever there is data to be written to
1194 * the client socket. Will delegate actual work according to whether
1195 * SASL SSF layers are enabled (thus requiring encryption calls)
1196 */
1197void vnc_client_write(void *opaque)
1198{
1199 long ret;
1200 VncState *vs = opaque;
1201
1202#ifdef CONFIG_VNC_SASL
1203 if (vs->sasl.conn &&
1204 vs->sasl.runSSF &&
1205 !vs->sasl.waitWriteSSF)
1206 ret = vnc_client_write_sasl(vs);
1207 else
1208#endif /* CONFIG_VNC_SASL */
1209 ret = vnc_client_write_plain(vs);
bellard24236862006-04-30 21:28:36 +00001210}
1211
aliguori5fb6c7a2009-03-06 20:27:23 +00001212void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
bellard24236862006-04-30 21:28:36 +00001213{
1214 vs->read_handler = func;
1215 vs->read_handler_expect = expecting;
1216}
1217
aliguori2f9606b2009-03-06 20:27:28 +00001218
1219/*
1220 * Called to read a chunk of data from the client socket. The data may
1221 * be the raw data, or may need to be further decoded by SASL.
1222 * The data will be read either straight from to the socket, or
1223 * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1224 *
1225 * NB, it is theoretically possible to have 2 layers of encryption,
1226 * both SASL, and this TLS layer. It is highly unlikely in practice
1227 * though, since SASL encryption will typically be a no-op if TLS
1228 * is active
1229 *
1230 * Returns the number of bytes read, which may be less than
1231 * the requested 'datalen' if the socket would block. Returns
1232 * -1 on error, and disconnects the client socket.
1233 */
1234long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001235{
bellardceb5caa2006-05-03 21:18:59 +00001236 long ret;
blueswir1eb38c522008-09-06 17:47:39 +00001237#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +00001238 if (vs->tls.session) {
aliguori28a76be2009-03-06 20:27:40 +00001239 ret = gnutls_read(vs->tls.session, data, datalen);
1240 if (ret < 0) {
1241 if (ret == GNUTLS_E_AGAIN)
1242 errno = EAGAIN;
1243 else
1244 errno = EIO;
1245 ret = -1;
1246 }
ths8d5d2d42007-08-25 01:37:51 +00001247 } else
1248#endif /* CONFIG_VNC_TLS */
Blue Swirlc5b76b32009-06-13 08:44:31 +00001249 ret = recv(vs->csock, (void *)data, datalen, 0);
aliguori23decc82009-03-20 15:59:18 +00001250 VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +00001251 return vnc_client_io_error(vs, ret, socket_error());
1252}
1253
1254
1255/*
1256 * Called to read data from the client socket to the input buffer,
1257 * when not using any SASL SSF encryption layers. Will read as much
1258 * data as possible without blocking.
1259 *
1260 * Returns the number of bytes read. Returns -1 on error, and
1261 * disconnects the client socket.
1262 */
1263static long vnc_client_read_plain(VncState *vs)
1264{
1265 int ret;
aliguori23decc82009-03-20 15:59:18 +00001266 VNC_DEBUG("Read plain %p size %zd offset %zd\n",
aliguori2f9606b2009-03-06 20:27:28 +00001267 vs->input.buffer, vs->input.capacity, vs->input.offset);
1268 buffer_reserve(&vs->input, 4096);
1269 ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
1270 if (!ret)
1271 return 0;
1272 vs->input.offset += ret;
1273 return ret;
1274}
1275
1276
1277/*
1278 * First function called whenever there is more data to be read from
1279 * the client socket. Will delegate actual work according to whether
1280 * SASL SSF layers are enabled (thus requiring decryption calls)
1281 */
1282void vnc_client_read(void *opaque)
1283{
1284 VncState *vs = opaque;
1285 long ret;
1286
1287#ifdef CONFIG_VNC_SASL
1288 if (vs->sasl.conn && vs->sasl.runSSF)
1289 ret = vnc_client_read_sasl(vs);
1290 else
1291#endif /* CONFIG_VNC_SASL */
1292 ret = vnc_client_read_plain(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001293 if (!ret) {
1294 if (vs->csock == -1)
1295 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001296 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001297 }
bellard24236862006-04-30 21:28:36 +00001298
bellard24236862006-04-30 21:28:36 +00001299 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
aliguori28a76be2009-03-06 20:27:40 +00001300 size_t len = vs->read_handler_expect;
1301 int ret;
bellard24236862006-04-30 21:28:36 +00001302
aliguori28a76be2009-03-06 20:27:40 +00001303 ret = vs->read_handler(vs, vs->input.buffer, len);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001304 if (vs->csock == -1) {
1305 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001306 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001307 }
bellard24236862006-04-30 21:28:36 +00001308
aliguori28a76be2009-03-06 20:27:40 +00001309 if (!ret) {
1310 memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
1311 vs->input.offset -= len;
1312 } else {
1313 vs->read_handler_expect = ret;
1314 }
bellard24236862006-04-30 21:28:36 +00001315 }
1316}
1317
aliguori5fb6c7a2009-03-06 20:27:23 +00001318void vnc_write(VncState *vs, const void *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001319{
1320 buffer_reserve(&vs->output, len);
1321
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001322 if (vs->csock != -1 && buffer_empty(&vs->output)) {
aliguori28a76be2009-03-06 20:27:40 +00001323 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
bellard24236862006-04-30 21:28:36 +00001324 }
1325
1326 buffer_append(&vs->output, data, len);
1327}
1328
aliguori5fb6c7a2009-03-06 20:27:23 +00001329void vnc_write_s32(VncState *vs, int32_t value)
bellard24236862006-04-30 21:28:36 +00001330{
1331 vnc_write_u32(vs, *(uint32_t *)&value);
1332}
1333
aliguori5fb6c7a2009-03-06 20:27:23 +00001334void vnc_write_u32(VncState *vs, uint32_t value)
bellard24236862006-04-30 21:28:36 +00001335{
1336 uint8_t buf[4];
1337
1338 buf[0] = (value >> 24) & 0xFF;
1339 buf[1] = (value >> 16) & 0xFF;
1340 buf[2] = (value >> 8) & 0xFF;
1341 buf[3] = value & 0xFF;
1342
1343 vnc_write(vs, buf, 4);
1344}
1345
aliguori5fb6c7a2009-03-06 20:27:23 +00001346void vnc_write_u16(VncState *vs, uint16_t value)
bellard24236862006-04-30 21:28:36 +00001347{
bellard64f5a132006-08-24 20:36:44 +00001348 uint8_t buf[2];
bellard24236862006-04-30 21:28:36 +00001349
1350 buf[0] = (value >> 8) & 0xFF;
1351 buf[1] = value & 0xFF;
1352
1353 vnc_write(vs, buf, 2);
1354}
1355
aliguori5fb6c7a2009-03-06 20:27:23 +00001356void vnc_write_u8(VncState *vs, uint8_t value)
bellard24236862006-04-30 21:28:36 +00001357{
1358 vnc_write(vs, (char *)&value, 1);
1359}
1360
aliguori5fb6c7a2009-03-06 20:27:23 +00001361void vnc_flush(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001362{
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001363 if (vs->csock != -1 && vs->output.offset)
aliguori28a76be2009-03-06 20:27:40 +00001364 vnc_client_write(vs);
bellard24236862006-04-30 21:28:36 +00001365}
1366
aliguori5fb6c7a2009-03-06 20:27:23 +00001367uint8_t read_u8(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001368{
1369 return data[offset];
1370}
1371
aliguori5fb6c7a2009-03-06 20:27:23 +00001372uint16_t read_u16(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001373{
1374 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
1375}
1376
aliguori5fb6c7a2009-03-06 20:27:23 +00001377int32_t read_s32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001378{
1379 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001380 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001381}
1382
aliguori5fb6c7a2009-03-06 20:27:23 +00001383uint32_t read_u32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001384{
1385 return ((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001386 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001387}
1388
ths60fe76f2007-12-16 03:02:09 +00001389static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
bellard24236862006-04-30 21:28:36 +00001390{
1391}
1392
bellard564c3372007-02-05 20:14:10 +00001393static void check_pointer_type_change(VncState *vs, int absolute)
1394{
aliguori29fa4ed2009-02-02 15:58:29 +00001395 if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
aliguori28a76be2009-03-06 20:27:40 +00001396 vnc_write_u8(vs, 0);
1397 vnc_write_u8(vs, 0);
1398 vnc_write_u16(vs, 1);
1399 vnc_framebuffer_update(vs, absolute, 0,
1400 ds_get_width(vs->ds), ds_get_height(vs->ds),
aliguori29fa4ed2009-02-02 15:58:29 +00001401 VNC_ENCODING_POINTER_TYPE_CHANGE);
aliguori28a76be2009-03-06 20:27:40 +00001402 vnc_flush(vs);
bellard564c3372007-02-05 20:14:10 +00001403 }
1404 vs->absolute = absolute;
1405}
1406
bellard24236862006-04-30 21:28:36 +00001407static void pointer_event(VncState *vs, int button_mask, int x, int y)
1408{
1409 int buttons = 0;
1410 int dz = 0;
1411
1412 if (button_mask & 0x01)
aliguori28a76be2009-03-06 20:27:40 +00001413 buttons |= MOUSE_EVENT_LBUTTON;
bellard24236862006-04-30 21:28:36 +00001414 if (button_mask & 0x02)
aliguori28a76be2009-03-06 20:27:40 +00001415 buttons |= MOUSE_EVENT_MBUTTON;
bellard24236862006-04-30 21:28:36 +00001416 if (button_mask & 0x04)
aliguori28a76be2009-03-06 20:27:40 +00001417 buttons |= MOUSE_EVENT_RBUTTON;
bellard24236862006-04-30 21:28:36 +00001418 if (button_mask & 0x08)
aliguori28a76be2009-03-06 20:27:40 +00001419 dz = -1;
bellard24236862006-04-30 21:28:36 +00001420 if (button_mask & 0x10)
aliguori28a76be2009-03-06 20:27:40 +00001421 dz = 1;
bellard564c3372007-02-05 20:14:10 +00001422
1423 if (vs->absolute) {
aliguori28a76be2009-03-06 20:27:40 +00001424 kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
1425 y * 0x7FFF / (ds_get_height(vs->ds) - 1),
1426 dz, buttons);
aliguori29fa4ed2009-02-02 15:58:29 +00001427 } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
aliguori28a76be2009-03-06 20:27:40 +00001428 x -= 0x7FFF;
1429 y -= 0x7FFF;
bellard564c3372007-02-05 20:14:10 +00001430
aliguori28a76be2009-03-06 20:27:40 +00001431 kbd_mouse_event(x, y, dz, buttons);
bellard24236862006-04-30 21:28:36 +00001432 } else {
aliguori28a76be2009-03-06 20:27:40 +00001433 if (vs->last_x != -1)
1434 kbd_mouse_event(x - vs->last_x,
1435 y - vs->last_y,
1436 dz, buttons);
1437 vs->last_x = x;
1438 vs->last_y = y;
bellard24236862006-04-30 21:28:36 +00001439 }
bellard564c3372007-02-05 20:14:10 +00001440
1441 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001442}
1443
bellard64f5a132006-08-24 20:36:44 +00001444static void reset_keys(VncState *vs)
1445{
1446 int i;
1447 for(i = 0; i < 256; i++) {
1448 if (vs->modifiers_state[i]) {
1449 if (i & 0x80)
1450 kbd_put_keycode(0xe0);
1451 kbd_put_keycode(i | 0x80);
1452 vs->modifiers_state[i] = 0;
1453 }
1454 }
1455}
1456
balroga528b802007-10-30 22:38:53 +00001457static void press_key(VncState *vs, int keysym)
1458{
aliguori753b4052009-02-16 14:59:30 +00001459 kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f);
1460 kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80);
balroga528b802007-10-30 22:38:53 +00001461}
1462
aliguori9ca313a2008-08-23 23:27:37 +00001463static void do_key_event(VncState *vs, int down, int keycode, int sym)
bellard24236862006-04-30 21:28:36 +00001464{
bellard64f5a132006-08-24 20:36:44 +00001465 /* QEMU console switch */
1466 switch(keycode) {
1467 case 0x2a: /* Left Shift */
1468 case 0x36: /* Right Shift */
1469 case 0x1d: /* Left CTRL */
1470 case 0x9d: /* Right CTRL */
1471 case 0x38: /* Left ALT */
1472 case 0xb8: /* Right ALT */
1473 if (down)
1474 vs->modifiers_state[keycode] = 1;
1475 else
1476 vs->modifiers_state[keycode] = 0;
1477 break;
ths5fafdf22007-09-16 21:08:06 +00001478 case 0x02 ... 0x0a: /* '1' to '9' keys */
bellard64f5a132006-08-24 20:36:44 +00001479 if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1480 /* Reset the modifiers sent to the current console */
1481 reset_keys(vs);
1482 console_select(keycode - 0x02);
1483 return;
1484 }
1485 break;
aliguori28a76be2009-03-06 20:27:40 +00001486 case 0x3a: /* CapsLock */
1487 case 0x45: /* NumLock */
balroga528b802007-10-30 22:38:53 +00001488 if (!down)
1489 vs->modifiers_state[keycode] ^= 1;
1490 break;
1491 }
1492
aliguori753b4052009-02-16 14:59:30 +00001493 if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
balroga528b802007-10-30 22:38:53 +00001494 /* If the numlock state needs to change then simulate an additional
1495 keypress before sending this one. This will happen if the user
1496 toggles numlock away from the VNC window.
1497 */
aliguori753b4052009-02-16 14:59:30 +00001498 if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
balroga528b802007-10-30 22:38:53 +00001499 if (!vs->modifiers_state[0x45]) {
1500 vs->modifiers_state[0x45] = 1;
1501 press_key(vs, 0xff7f);
1502 }
1503 } else {
1504 if (vs->modifiers_state[0x45]) {
1505 vs->modifiers_state[0x45] = 0;
1506 press_key(vs, 0xff7f);
1507 }
1508 }
bellard64f5a132006-08-24 20:36:44 +00001509 }
bellard24236862006-04-30 21:28:36 +00001510
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001511 if ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z')) {
1512 /* If the capslock state needs to change then simulate an additional
1513 keypress before sending this one. This will happen if the user
1514 toggles capslock away from the VNC window.
1515 */
1516 int uppercase = !!(sym >= 'A' && sym <= 'Z');
1517 int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
1518 int capslock = !!(vs->modifiers_state[0x3a]);
1519 if (capslock) {
1520 if (uppercase == shift) {
1521 vs->modifiers_state[0x3a] = 0;
1522 press_key(vs, 0xffe5);
1523 }
1524 } else {
1525 if (uppercase != shift) {
1526 vs->modifiers_state[0x3a] = 1;
1527 press_key(vs, 0xffe5);
1528 }
1529 }
1530 }
1531
bellard64f5a132006-08-24 20:36:44 +00001532 if (is_graphic_console()) {
1533 if (keycode & 0x80)
1534 kbd_put_keycode(0xe0);
1535 if (down)
1536 kbd_put_keycode(keycode & 0x7f);
1537 else
1538 kbd_put_keycode(keycode | 0x80);
1539 } else {
1540 /* QEMU console emulation */
1541 if (down) {
Gerd Hoffmannbb0a18e2009-06-11 11:32:14 +02001542 int numlock = vs->modifiers_state[0x45];
bellard64f5a132006-08-24 20:36:44 +00001543 switch (keycode) {
1544 case 0x2a: /* Left Shift */
1545 case 0x36: /* Right Shift */
1546 case 0x1d: /* Left CTRL */
1547 case 0x9d: /* Right CTRL */
1548 case 0x38: /* Left ALT */
1549 case 0xb8: /* Right ALT */
1550 break;
1551 case 0xc8:
1552 kbd_put_keysym(QEMU_KEY_UP);
1553 break;
1554 case 0xd0:
1555 kbd_put_keysym(QEMU_KEY_DOWN);
1556 break;
1557 case 0xcb:
1558 kbd_put_keysym(QEMU_KEY_LEFT);
1559 break;
1560 case 0xcd:
1561 kbd_put_keysym(QEMU_KEY_RIGHT);
1562 break;
1563 case 0xd3:
1564 kbd_put_keysym(QEMU_KEY_DELETE);
1565 break;
1566 case 0xc7:
1567 kbd_put_keysym(QEMU_KEY_HOME);
1568 break;
1569 case 0xcf:
1570 kbd_put_keysym(QEMU_KEY_END);
1571 break;
1572 case 0xc9:
1573 kbd_put_keysym(QEMU_KEY_PAGEUP);
1574 break;
1575 case 0xd1:
1576 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1577 break;
Gerd Hoffmannbb0a18e2009-06-11 11:32:14 +02001578
1579 case 0x47:
1580 kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
1581 break;
1582 case 0x48:
1583 kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
1584 break;
1585 case 0x49:
1586 kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
1587 break;
1588 case 0x4b:
1589 kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
1590 break;
1591 case 0x4c:
1592 kbd_put_keysym('5');
1593 break;
1594 case 0x4d:
1595 kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
1596 break;
1597 case 0x4f:
1598 kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
1599 break;
1600 case 0x50:
1601 kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
1602 break;
1603 case 0x51:
1604 kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
1605 break;
1606 case 0x52:
1607 kbd_put_keysym('0');
1608 break;
1609 case 0x53:
1610 kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
1611 break;
1612
1613 case 0xb5:
1614 kbd_put_keysym('/');
1615 break;
1616 case 0x37:
1617 kbd_put_keysym('*');
1618 break;
1619 case 0x4a:
1620 kbd_put_keysym('-');
1621 break;
1622 case 0x4e:
1623 kbd_put_keysym('+');
1624 break;
1625 case 0x9c:
1626 kbd_put_keysym('\n');
1627 break;
1628
bellard64f5a132006-08-24 20:36:44 +00001629 default:
1630 kbd_put_keysym(sym);
1631 break;
1632 }
1633 }
1634 }
bellard24236862006-04-30 21:28:36 +00001635}
1636
bellardbdbd7672006-05-01 21:44:22 +00001637static void key_event(VncState *vs, int down, uint32_t sym)
1638{
aliguori9ca313a2008-08-23 23:27:37 +00001639 int keycode;
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001640 int lsym = sym;
aliguori9ca313a2008-08-23 23:27:37 +00001641
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001642 if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) {
1643 lsym = lsym - 'A' + 'a';
1644 }
aliguori9ca313a2008-08-23 23:27:37 +00001645
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001646 keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF);
aliguori9ca313a2008-08-23 23:27:37 +00001647 do_key_event(vs, down, keycode, sym);
1648}
1649
1650static void ext_key_event(VncState *vs, int down,
1651 uint32_t sym, uint16_t keycode)
1652{
1653 /* if the user specifies a keyboard layout, always use it */
1654 if (keyboard_layout)
1655 key_event(vs, down, sym);
1656 else
1657 do_key_event(vs, down, keycode, sym);
bellardbdbd7672006-05-01 21:44:22 +00001658}
1659
bellard24236862006-04-30 21:28:36 +00001660static void framebuffer_update_request(VncState *vs, int incremental,
aliguori28a76be2009-03-06 20:27:40 +00001661 int x_position, int y_position,
1662 int w, int h)
bellard24236862006-04-30 21:28:36 +00001663{
aliguori0e1f5a02008-11-24 19:29:13 +00001664 if (x_position > ds_get_width(vs->ds))
1665 x_position = ds_get_width(vs->ds);
1666 if (y_position > ds_get_height(vs->ds))
1667 y_position = ds_get_height(vs->ds);
1668 if (x_position + w >= ds_get_width(vs->ds))
1669 w = ds_get_width(vs->ds) - x_position;
1670 if (y_position + h >= ds_get_height(vs->ds))
1671 h = ds_get_height(vs->ds) - y_position;
thscf2d3852007-04-29 01:53:20 +00001672
bellard24236862006-04-30 21:28:36 +00001673 int i;
1674 vs->need_update = 1;
1675 if (!incremental) {
Gerd Hoffmann24cf0a62009-04-27 16:39:52 +02001676 vs->force_update = 1;
aliguori28a76be2009-03-06 20:27:40 +00001677 for (i = 0; i < h; i++) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +01001678 vnc_set_bits(vs->dirty[y_position + i],
aliguori6baebed2009-03-20 15:59:14 +00001679 (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
aliguori28a76be2009-03-06 20:27:40 +00001680 }
bellard24236862006-04-30 21:28:36 +00001681 }
1682}
1683
aliguori9ca313a2008-08-23 23:27:37 +00001684static void send_ext_key_event_ack(VncState *vs)
1685{
1686 vnc_write_u8(vs, 0);
1687 vnc_write_u8(vs, 0);
1688 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001689 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1690 VNC_ENCODING_EXT_KEY_EVENT);
aliguori9ca313a2008-08-23 23:27:37 +00001691 vnc_flush(vs);
1692}
1693
malc429a8ed2008-12-01 20:57:48 +00001694static void send_ext_audio_ack(VncState *vs)
1695{
1696 vnc_write_u8(vs, 0);
1697 vnc_write_u8(vs, 0);
1698 vnc_write_u16(vs, 1);
aliguori29fa4ed2009-02-02 15:58:29 +00001699 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1700 VNC_ENCODING_AUDIO);
malc429a8ed2008-12-01 20:57:48 +00001701 vnc_flush(vs);
1702}
1703
bellard24236862006-04-30 21:28:36 +00001704static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1705{
1706 int i;
aliguori29fa4ed2009-02-02 15:58:29 +00001707 unsigned int enc = 0;
bellard24236862006-04-30 21:28:36 +00001708
aliguori059cef42009-02-02 15:58:54 +00001709 vnc_zlib_init(vs);
aliguori29fa4ed2009-02-02 15:58:29 +00001710 vs->features = 0;
aliguorifb437312009-02-02 15:58:43 +00001711 vs->vnc_encoding = 0;
1712 vs->tight_compression = 9;
1713 vs->tight_quality = 9;
bellard564c3372007-02-05 20:14:10 +00001714 vs->absolute = -1;
bellard24236862006-04-30 21:28:36 +00001715
1716 for (i = n_encodings - 1; i >= 0; i--) {
aliguori29fa4ed2009-02-02 15:58:29 +00001717 enc = encodings[i];
1718 switch (enc) {
1719 case VNC_ENCODING_RAW:
aliguorifb437312009-02-02 15:58:43 +00001720 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001721 break;
1722 case VNC_ENCODING_COPYRECT:
aliguori753b4052009-02-16 14:59:30 +00001723 vs->features |= VNC_FEATURE_COPYRECT_MASK;
aliguori29fa4ed2009-02-02 15:58:29 +00001724 break;
1725 case VNC_ENCODING_HEXTILE:
1726 vs->features |= VNC_FEATURE_HEXTILE_MASK;
aliguorifb437312009-02-02 15:58:43 +00001727 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001728 break;
aliguori059cef42009-02-02 15:58:54 +00001729 case VNC_ENCODING_ZLIB:
1730 vs->features |= VNC_FEATURE_ZLIB_MASK;
1731 vs->vnc_encoding = enc;
1732 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001733 case VNC_ENCODING_DESKTOPRESIZE:
1734 vs->features |= VNC_FEATURE_RESIZE_MASK;
1735 break;
1736 case VNC_ENCODING_POINTER_TYPE_CHANGE:
1737 vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
1738 break;
1739 case VNC_ENCODING_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00001740 send_ext_key_event_ack(vs);
1741 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001742 case VNC_ENCODING_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00001743 send_ext_audio_ack(vs);
1744 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001745 case VNC_ENCODING_WMVi:
1746 vs->features |= VNC_FEATURE_WMVI_MASK;
aliguorica4cca42008-09-15 16:05:16 +00001747 break;
aliguorifb437312009-02-02 15:58:43 +00001748 case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
1749 vs->tight_compression = (enc & 0x0F);
1750 break;
1751 case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
1752 vs->tight_quality = (enc & 0x0F);
1753 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001754 default:
1755 VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
1756 break;
1757 }
bellard24236862006-04-30 21:28:36 +00001758 }
bellard564c3372007-02-05 20:14:10 +00001759
1760 check_pointer_type_change(vs, kbd_mouse_is_absolute());
bellard24236862006-04-30 21:28:36 +00001761}
1762
aliguori6cec5482009-01-15 22:17:38 +00001763static void set_pixel_conversion(VncState *vs)
1764{
1765 if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
1766 (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) &&
1767 !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
1768 vs->write_pixels = vnc_write_pixels_copy;
1769 switch (vs->ds->surface->pf.bits_per_pixel) {
1770 case 8:
1771 vs->send_hextile_tile = send_hextile_tile_8;
1772 break;
1773 case 16:
1774 vs->send_hextile_tile = send_hextile_tile_16;
1775 break;
1776 case 32:
1777 vs->send_hextile_tile = send_hextile_tile_32;
1778 break;
1779 }
1780 } else {
1781 vs->write_pixels = vnc_write_pixels_generic;
1782 switch (vs->ds->surface->pf.bits_per_pixel) {
1783 case 8:
1784 vs->send_hextile_tile = send_hextile_tile_generic_8;
1785 break;
1786 case 16:
1787 vs->send_hextile_tile = send_hextile_tile_generic_16;
1788 break;
1789 case 32:
1790 vs->send_hextile_tile = send_hextile_tile_generic_32;
1791 break;
1792 }
1793 }
1794}
1795
bellard24236862006-04-30 21:28:36 +00001796static void set_pixel_format(VncState *vs,
aliguori28a76be2009-03-06 20:27:40 +00001797 int bits_per_pixel, int depth,
1798 int big_endian_flag, int true_color_flag,
1799 int red_max, int green_max, int blue_max,
1800 int red_shift, int green_shift, int blue_shift)
bellard24236862006-04-30 21:28:36 +00001801{
bellard35127792006-05-14 18:11:49 +00001802 if (!true_color_flag) {
aliguori28a76be2009-03-06 20:27:40 +00001803 vnc_client_error(vs);
bellard35127792006-05-14 18:11:49 +00001804 return;
1805 }
aliguori7eac3a82008-09-15 16:03:41 +00001806
Stefano Stabellini1fc62412009-08-03 10:54:32 +01001807 vs->clientds = *(vs->vd->guest.ds);
aliguori6cec5482009-01-15 22:17:38 +00001808 vs->clientds.pf.rmax = red_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001809 count_bits(vs->clientds.pf.rbits, red_max);
aliguori6cec5482009-01-15 22:17:38 +00001810 vs->clientds.pf.rshift = red_shift;
1811 vs->clientds.pf.rmask = red_max << red_shift;
1812 vs->clientds.pf.gmax = green_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001813 count_bits(vs->clientds.pf.gbits, green_max);
aliguori6cec5482009-01-15 22:17:38 +00001814 vs->clientds.pf.gshift = green_shift;
1815 vs->clientds.pf.gmask = green_max << green_shift;
1816 vs->clientds.pf.bmax = blue_max;
aliguori90a1e3c2009-01-26 15:37:30 +00001817 count_bits(vs->clientds.pf.bbits, blue_max);
aliguori6cec5482009-01-15 22:17:38 +00001818 vs->clientds.pf.bshift = blue_shift;
1819 vs->clientds.pf.bmask = blue_max << blue_shift;
1820 vs->clientds.pf.bits_per_pixel = bits_per_pixel;
1821 vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
1822 vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
1823 vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
bellard24236862006-04-30 21:28:36 +00001824
aliguori6cec5482009-01-15 22:17:38 +00001825 set_pixel_conversion(vs);
bellard24236862006-04-30 21:28:36 +00001826
1827 vga_hw_invalidate();
1828 vga_hw_update();
1829}
1830
aliguorica4cca42008-09-15 16:05:16 +00001831static void pixel_format_message (VncState *vs) {
1832 char pad[3] = { 0, 0, 0 };
1833
aliguori6cec5482009-01-15 22:17:38 +00001834 vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
1835 vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
aliguorica4cca42008-09-15 16:05:16 +00001836
Juan Quintelae2542fe2009-07-27 16:13:06 +02001837#ifdef HOST_WORDS_BIGENDIAN
aliguorica4cca42008-09-15 16:05:16 +00001838 vnc_write_u8(vs, 1); /* big-endian-flag */
1839#else
1840 vnc_write_u8(vs, 0); /* big-endian-flag */
1841#endif
1842 vnc_write_u8(vs, 1); /* true-color-flag */
aliguori6cec5482009-01-15 22:17:38 +00001843 vnc_write_u16(vs, vs->ds->surface->pf.rmax); /* red-max */
1844 vnc_write_u16(vs, vs->ds->surface->pf.gmax); /* green-max */
1845 vnc_write_u16(vs, vs->ds->surface->pf.bmax); /* blue-max */
1846 vnc_write_u8(vs, vs->ds->surface->pf.rshift); /* red-shift */
1847 vnc_write_u8(vs, vs->ds->surface->pf.gshift); /* green-shift */
1848 vnc_write_u8(vs, vs->ds->surface->pf.bshift); /* blue-shift */
1849 if (vs->ds->surface->pf.bits_per_pixel == 32)
aliguorica4cca42008-09-15 16:05:16 +00001850 vs->send_hextile_tile = send_hextile_tile_32;
aliguori6cec5482009-01-15 22:17:38 +00001851 else if (vs->ds->surface->pf.bits_per_pixel == 16)
aliguorica4cca42008-09-15 16:05:16 +00001852 vs->send_hextile_tile = send_hextile_tile_16;
aliguori6cec5482009-01-15 22:17:38 +00001853 else if (vs->ds->surface->pf.bits_per_pixel == 8)
aliguorica4cca42008-09-15 16:05:16 +00001854 vs->send_hextile_tile = send_hextile_tile_8;
aliguori6cec5482009-01-15 22:17:38 +00001855 vs->clientds = *(vs->ds->surface);
aurel323cded542009-04-07 19:57:09 +00001856 vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
aliguorica4cca42008-09-15 16:05:16 +00001857 vs->write_pixels = vnc_write_pixels_copy;
1858
1859 vnc_write(vs, pad, 3); /* padding */
1860}
1861
aliguori7d957bd2009-01-15 22:14:11 +00001862static void vnc_dpy_setdata(DisplayState *ds)
1863{
1864 /* We don't have to do anything */
1865}
1866
aliguori753b4052009-02-16 14:59:30 +00001867static void vnc_colordepth(VncState *vs)
aliguori7eac3a82008-09-15 16:03:41 +00001868{
aliguori753b4052009-02-16 14:59:30 +00001869 if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
aliguorica4cca42008-09-15 16:05:16 +00001870 /* Sending a WMVi message to notify the client*/
1871 vnc_write_u8(vs, 0); /* msg id */
1872 vnc_write_u8(vs, 0);
1873 vnc_write_u16(vs, 1); /* number of rects */
aliguori753b4052009-02-16 14:59:30 +00001874 vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds),
1875 ds_get_height(vs->ds), VNC_ENCODING_WMVi);
aliguorica4cca42008-09-15 16:05:16 +00001876 pixel_format_message(vs);
1877 vnc_flush(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001878 } else {
aliguori6cec5482009-01-15 22:17:38 +00001879 set_pixel_conversion(vs);
aliguori7eac3a82008-09-15 16:03:41 +00001880 }
1881}
1882
ths60fe76f2007-12-16 03:02:09 +00001883static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001884{
1885 int i;
1886 uint16_t limit;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01001887 VncDisplay *vd = vs->vd;
1888
1889 if (data[0] > 3) {
1890 vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
1891 if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval))
1892 qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
1893 }
bellard24236862006-04-30 21:28:36 +00001894
1895 switch (data[0]) {
1896 case 0:
aliguori28a76be2009-03-06 20:27:40 +00001897 if (len == 1)
1898 return 20;
bellard24236862006-04-30 21:28:36 +00001899
aliguori28a76be2009-03-06 20:27:40 +00001900 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
1901 read_u8(data, 6), read_u8(data, 7),
1902 read_u16(data, 8), read_u16(data, 10),
1903 read_u16(data, 12), read_u8(data, 14),
1904 read_u8(data, 15), read_u8(data, 16));
1905 break;
bellard24236862006-04-30 21:28:36 +00001906 case 2:
aliguori28a76be2009-03-06 20:27:40 +00001907 if (len == 1)
1908 return 4;
bellard24236862006-04-30 21:28:36 +00001909
aliguori28a76be2009-03-06 20:27:40 +00001910 if (len == 4) {
aliguori69dd5c92008-12-22 21:06:23 +00001911 limit = read_u16(data, 2);
1912 if (limit > 0)
1913 return 4 + (limit * 4);
1914 } else
1915 limit = read_u16(data, 2);
bellard24236862006-04-30 21:28:36 +00001916
aliguori28a76be2009-03-06 20:27:40 +00001917 for (i = 0; i < limit; i++) {
1918 int32_t val = read_s32(data, 4 + (i * 4));
1919 memcpy(data + 4 + (i * 4), &val, sizeof(val));
1920 }
bellard24236862006-04-30 21:28:36 +00001921
aliguori28a76be2009-03-06 20:27:40 +00001922 set_encodings(vs, (int32_t *)(data + 4), limit);
1923 break;
bellard24236862006-04-30 21:28:36 +00001924 case 3:
aliguori28a76be2009-03-06 20:27:40 +00001925 if (len == 1)
1926 return 10;
bellard24236862006-04-30 21:28:36 +00001927
aliguori28a76be2009-03-06 20:27:40 +00001928 framebuffer_update_request(vs,
1929 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
1930 read_u16(data, 6), read_u16(data, 8));
1931 break;
bellard24236862006-04-30 21:28:36 +00001932 case 4:
aliguori28a76be2009-03-06 20:27:40 +00001933 if (len == 1)
1934 return 8;
bellard24236862006-04-30 21:28:36 +00001935
aliguori28a76be2009-03-06 20:27:40 +00001936 key_event(vs, read_u8(data, 1), read_u32(data, 4));
1937 break;
bellard24236862006-04-30 21:28:36 +00001938 case 5:
aliguori28a76be2009-03-06 20:27:40 +00001939 if (len == 1)
1940 return 6;
bellard24236862006-04-30 21:28:36 +00001941
aliguori28a76be2009-03-06 20:27:40 +00001942 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
1943 break;
bellard24236862006-04-30 21:28:36 +00001944 case 6:
aliguori28a76be2009-03-06 20:27:40 +00001945 if (len == 1)
1946 return 8;
bellard24236862006-04-30 21:28:36 +00001947
aliguori28a76be2009-03-06 20:27:40 +00001948 if (len == 8) {
thsbaa76662007-09-13 12:41:42 +00001949 uint32_t dlen = read_u32(data, 4);
1950 if (dlen > 0)
1951 return 8 + dlen;
1952 }
bellard24236862006-04-30 21:28:36 +00001953
aliguori28a76be2009-03-06 20:27:40 +00001954 client_cut_text(vs, read_u32(data, 4), data + 8);
1955 break;
aliguori9ca313a2008-08-23 23:27:37 +00001956 case 255:
1957 if (len == 1)
1958 return 2;
1959
1960 switch (read_u8(data, 1)) {
1961 case 0:
1962 if (len == 2)
1963 return 12;
1964
1965 ext_key_event(vs, read_u16(data, 2),
1966 read_u32(data, 4), read_u32(data, 8));
1967 break;
malc429a8ed2008-12-01 20:57:48 +00001968 case 1:
1969 if (len == 2)
1970 return 4;
1971
1972 switch (read_u16 (data, 2)) {
1973 case 0:
1974 audio_add(vs);
1975 break;
1976 case 1:
1977 audio_del(vs);
1978 break;
1979 case 2:
1980 if (len == 4)
1981 return 10;
1982 switch (read_u8(data, 4)) {
1983 case 0: vs->as.fmt = AUD_FMT_U8; break;
1984 case 1: vs->as.fmt = AUD_FMT_S8; break;
1985 case 2: vs->as.fmt = AUD_FMT_U16; break;
1986 case 3: vs->as.fmt = AUD_FMT_S16; break;
1987 case 4: vs->as.fmt = AUD_FMT_U32; break;
1988 case 5: vs->as.fmt = AUD_FMT_S32; break;
1989 default:
1990 printf("Invalid audio format %d\n", read_u8(data, 4));
1991 vnc_client_error(vs);
1992 break;
1993 }
1994 vs->as.nchannels = read_u8(data, 5);
1995 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
1996 printf("Invalid audio channel coount %d\n",
1997 read_u8(data, 5));
1998 vnc_client_error(vs);
1999 break;
2000 }
2001 vs->as.freq = read_u32(data, 6);
2002 break;
2003 default:
2004 printf ("Invalid audio message %d\n", read_u8(data, 4));
2005 vnc_client_error(vs);
2006 break;
2007 }
2008 break;
2009
aliguori9ca313a2008-08-23 23:27:37 +00002010 default:
2011 printf("Msg: %d\n", read_u16(data, 0));
2012 vnc_client_error(vs);
2013 break;
2014 }
2015 break;
bellard24236862006-04-30 21:28:36 +00002016 default:
aliguori28a76be2009-03-06 20:27:40 +00002017 printf("Msg: %d\n", data[0]);
2018 vnc_client_error(vs);
2019 break;
bellard24236862006-04-30 21:28:36 +00002020 }
ths5fafdf22007-09-16 21:08:06 +00002021
bellard24236862006-04-30 21:28:36 +00002022 vnc_read_when(vs, protocol_client_msg, 1);
2023 return 0;
2024}
2025
ths60fe76f2007-12-16 03:02:09 +00002026static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00002027{
thsc35734b2007-03-19 15:17:08 +00002028 char buf[1024];
2029 int size;
bellard24236862006-04-30 21:28:36 +00002030
aliguori0e1f5a02008-11-24 19:29:13 +00002031 vnc_write_u16(vs, ds_get_width(vs->ds));
2032 vnc_write_u16(vs, ds_get_height(vs->ds));
bellard24236862006-04-30 21:28:36 +00002033
aliguorica4cca42008-09-15 16:05:16 +00002034 pixel_format_message(vs);
bellard24236862006-04-30 21:28:36 +00002035
thsc35734b2007-03-19 15:17:08 +00002036 if (qemu_name)
2037 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
2038 else
2039 size = snprintf(buf, sizeof(buf), "QEMU");
2040
2041 vnc_write_u32(vs, size);
2042 vnc_write(vs, buf, size);
bellard24236862006-04-30 21:28:36 +00002043 vnc_flush(vs);
2044
2045 vnc_read_when(vs, protocol_client_msg, 1);
2046
2047 return 0;
2048}
2049
aliguori5fb6c7a2009-03-06 20:27:23 +00002050void start_client_init(VncState *vs)
2051{
2052 vnc_read_when(vs, protocol_client_init, 1);
2053}
2054
ths70848512007-08-25 01:37:05 +00002055static void make_challenge(VncState *vs)
bellard24236862006-04-30 21:28:36 +00002056{
ths70848512007-08-25 01:37:05 +00002057 int i;
bellard24236862006-04-30 21:28:36 +00002058
ths70848512007-08-25 01:37:05 +00002059 srand(time(NULL)+getpid()+getpid()*987654+rand());
bellard24236862006-04-30 21:28:36 +00002060
ths70848512007-08-25 01:37:05 +00002061 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
2062 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
2063}
2064
ths60fe76f2007-12-16 03:02:09 +00002065static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002066{
ths60fe76f2007-12-16 03:02:09 +00002067 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
ths70848512007-08-25 01:37:05 +00002068 int i, j, pwlen;
ths60fe76f2007-12-16 03:02:09 +00002069 unsigned char key[8];
ths70848512007-08-25 01:37:05 +00002070
aliguori753b4052009-02-16 14:59:30 +00002071 if (!vs->vd->password || !vs->vd->password[0]) {
aliguori28a76be2009-03-06 20:27:40 +00002072 VNC_DEBUG("No password configured on server");
2073 vnc_write_u32(vs, 1); /* Reject auth */
2074 if (vs->minor >= 8) {
2075 static const char err[] = "Authentication failed";
2076 vnc_write_u32(vs, sizeof(err));
2077 vnc_write(vs, err, sizeof(err));
2078 }
2079 vnc_flush(vs);
2080 vnc_client_error(vs);
2081 return 0;
bellard24236862006-04-30 21:28:36 +00002082 }
2083
ths70848512007-08-25 01:37:05 +00002084 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
2085
2086 /* Calculate the expected challenge response */
aliguori753b4052009-02-16 14:59:30 +00002087 pwlen = strlen(vs->vd->password);
ths70848512007-08-25 01:37:05 +00002088 for (i=0; i<sizeof(key); i++)
aliguori753b4052009-02-16 14:59:30 +00002089 key[i] = i<pwlen ? vs->vd->password[i] : 0;
ths70848512007-08-25 01:37:05 +00002090 deskey(key, EN0);
2091 for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
2092 des(response+j, response+j);
2093
2094 /* Compare expected vs actual challenge response */
2095 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
aliguori28a76be2009-03-06 20:27:40 +00002096 VNC_DEBUG("Client challenge reponse did not match\n");
2097 vnc_write_u32(vs, 1); /* Reject auth */
2098 if (vs->minor >= 8) {
2099 static const char err[] = "Authentication failed";
2100 vnc_write_u32(vs, sizeof(err));
2101 vnc_write(vs, err, sizeof(err));
2102 }
2103 vnc_flush(vs);
2104 vnc_client_error(vs);
ths70848512007-08-25 01:37:05 +00002105 } else {
aliguori28a76be2009-03-06 20:27:40 +00002106 VNC_DEBUG("Accepting VNC challenge response\n");
2107 vnc_write_u32(vs, 0); /* Accept auth */
2108 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002109
aliguori5fb6c7a2009-03-06 20:27:23 +00002110 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00002111 }
2112 return 0;
2113}
2114
aliguori5fb6c7a2009-03-06 20:27:23 +00002115void start_auth_vnc(VncState *vs)
ths70848512007-08-25 01:37:05 +00002116{
2117 make_challenge(vs);
2118 /* Send client a 'random' challenge */
2119 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
bellard24236862006-04-30 21:28:36 +00002120 vnc_flush(vs);
2121
ths70848512007-08-25 01:37:05 +00002122 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
ths70848512007-08-25 01:37:05 +00002123}
2124
ths8d5d2d42007-08-25 01:37:51 +00002125
ths60fe76f2007-12-16 03:02:09 +00002126static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002127{
2128 /* We only advertise 1 auth scheme at a time, so client
2129 * must pick the one we sent. Verify this */
aliguori753b4052009-02-16 14:59:30 +00002130 if (data[0] != vs->vd->auth) { /* Reject auth */
aliguori1263b7d2009-03-06 20:27:32 +00002131 VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
ths70848512007-08-25 01:37:05 +00002132 vnc_write_u32(vs, 1);
2133 if (vs->minor >= 8) {
2134 static const char err[] = "Authentication failed";
2135 vnc_write_u32(vs, sizeof(err));
2136 vnc_write(vs, err, sizeof(err));
2137 }
2138 vnc_client_error(vs);
2139 } else { /* Accept requested auth */
2140 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
aliguori753b4052009-02-16 14:59:30 +00002141 switch (vs->vd->auth) {
ths70848512007-08-25 01:37:05 +00002142 case VNC_AUTH_NONE:
2143 VNC_DEBUG("Accept auth none\n");
balroga26c97a2007-10-31 01:58:56 +00002144 if (vs->minor >= 8) {
2145 vnc_write_u32(vs, 0); /* Accept auth completion */
2146 vnc_flush(vs);
2147 }
aliguori5fb6c7a2009-03-06 20:27:23 +00002148 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00002149 break;
2150
2151 case VNC_AUTH_VNC:
2152 VNC_DEBUG("Start VNC auth\n");
aliguori5fb6c7a2009-03-06 20:27:23 +00002153 start_auth_vnc(vs);
2154 break;
ths70848512007-08-25 01:37:05 +00002155
blueswir1eb38c522008-09-06 17:47:39 +00002156#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002157 case VNC_AUTH_VENCRYPT:
2158 VNC_DEBUG("Accept VeNCrypt auth\n");;
aliguori5fb6c7a2009-03-06 20:27:23 +00002159 start_auth_vencrypt(vs);
2160 break;
ths8d5d2d42007-08-25 01:37:51 +00002161#endif /* CONFIG_VNC_TLS */
2162
aliguori2f9606b2009-03-06 20:27:28 +00002163#ifdef CONFIG_VNC_SASL
2164 case VNC_AUTH_SASL:
2165 VNC_DEBUG("Accept SASL auth\n");
2166 start_auth_sasl(vs);
2167 break;
2168#endif /* CONFIG_VNC_SASL */
2169
ths70848512007-08-25 01:37:05 +00002170 default: /* Should not be possible, but just in case */
aliguori1263b7d2009-03-06 20:27:32 +00002171 VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002172 vnc_write_u8(vs, 1);
2173 if (vs->minor >= 8) {
2174 static const char err[] = "Authentication failed";
2175 vnc_write_u32(vs, sizeof(err));
2176 vnc_write(vs, err, sizeof(err));
2177 }
2178 vnc_client_error(vs);
2179 }
2180 }
2181 return 0;
2182}
2183
ths60fe76f2007-12-16 03:02:09 +00002184static int protocol_version(VncState *vs, uint8_t *version, size_t len)
ths70848512007-08-25 01:37:05 +00002185{
2186 char local[13];
2187
2188 memcpy(local, version, 12);
2189 local[12] = 0;
2190
2191 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
aliguori28a76be2009-03-06 20:27:40 +00002192 VNC_DEBUG("Malformed protocol version %s\n", local);
2193 vnc_client_error(vs);
2194 return 0;
ths70848512007-08-25 01:37:05 +00002195 }
2196 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2197 if (vs->major != 3 ||
aliguori28a76be2009-03-06 20:27:40 +00002198 (vs->minor != 3 &&
2199 vs->minor != 4 &&
2200 vs->minor != 5 &&
2201 vs->minor != 7 &&
2202 vs->minor != 8)) {
2203 VNC_DEBUG("Unsupported client version\n");
2204 vnc_write_u32(vs, VNC_AUTH_INVALID);
2205 vnc_flush(vs);
2206 vnc_client_error(vs);
2207 return 0;
ths70848512007-08-25 01:37:05 +00002208 }
thsb0566f42007-09-30 13:01:15 +00002209 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
ths70848512007-08-25 01:37:05 +00002210 * as equivalent to v3.3 by servers
2211 */
thsb0566f42007-09-30 13:01:15 +00002212 if (vs->minor == 4 || vs->minor == 5)
aliguori28a76be2009-03-06 20:27:40 +00002213 vs->minor = 3;
ths70848512007-08-25 01:37:05 +00002214
2215 if (vs->minor == 3) {
aliguori28a76be2009-03-06 20:27:40 +00002216 if (vs->vd->auth == VNC_AUTH_NONE) {
ths70848512007-08-25 01:37:05 +00002217 VNC_DEBUG("Tell client auth none\n");
aliguori753b4052009-02-16 14:59:30 +00002218 vnc_write_u32(vs, vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002219 vnc_flush(vs);
aliguori28a76be2009-03-06 20:27:40 +00002220 start_client_init(vs);
aliguori753b4052009-02-16 14:59:30 +00002221 } else if (vs->vd->auth == VNC_AUTH_VNC) {
ths70848512007-08-25 01:37:05 +00002222 VNC_DEBUG("Tell client VNC auth\n");
aliguori753b4052009-02-16 14:59:30 +00002223 vnc_write_u32(vs, vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002224 vnc_flush(vs);
2225 start_auth_vnc(vs);
2226 } else {
aliguori753b4052009-02-16 14:59:30 +00002227 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
ths70848512007-08-25 01:37:05 +00002228 vnc_write_u32(vs, VNC_AUTH_INVALID);
2229 vnc_flush(vs);
2230 vnc_client_error(vs);
2231 }
2232 } else {
aliguori28a76be2009-03-06 20:27:40 +00002233 VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
2234 vnc_write_u8(vs, 1); /* num auth */
2235 vnc_write_u8(vs, vs->vd->auth);
2236 vnc_read_when(vs, protocol_client_auth, 1);
2237 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002238 }
bellard24236862006-04-30 21:28:36 +00002239
2240 return 0;
2241}
2242
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002243static int vnc_refresh_server_surface(VncDisplay *vd)
2244{
2245 int y;
2246 uint8_t *guest_row;
2247 uint8_t *server_row;
2248 int cmp_bytes;
2249 uint32_t width_mask[VNC_DIRTY_WORDS];
2250 VncState *vs = NULL;
2251 int has_dirty = 0;
2252
2253 /*
2254 * Walk through the guest dirty map.
2255 * Check and copy modified bits from guest to server surface.
2256 * Update server dirty map.
2257 */
2258 vnc_set_bits(width_mask, (ds_get_width(vd->ds) / 16), VNC_DIRTY_WORDS);
2259 cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
2260 guest_row = vd->guest.ds->data;
2261 server_row = vd->server->data;
2262 for (y = 0; y < vd->guest.ds->height; y++) {
2263 if (vnc_and_bits(vd->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
2264 int x;
2265 uint8_t *guest_ptr;
2266 uint8_t *server_ptr;
2267
2268 guest_ptr = guest_row;
2269 server_ptr = server_row;
2270
2271 for (x = 0; x < vd->guest.ds->width;
2272 x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
2273 if (!vnc_get_bit(vd->guest.dirty[y], (x / 16)))
2274 continue;
2275 vnc_clear_bit(vd->guest.dirty[y], (x / 16));
2276 if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
2277 continue;
2278 memcpy(server_ptr, guest_ptr, cmp_bytes);
2279 vs = vd->clients;
2280 while (vs != NULL) {
2281 vnc_set_bit(vs->dirty[y], (x / 16));
2282 vs = vs->next;
2283 }
2284 has_dirty++;
2285 }
2286 }
2287 guest_row += ds_get_linesize(vd->ds);
2288 server_row += ds_get_linesize(vd->ds);
2289 }
2290 return has_dirty;
2291}
2292
Stefano Stabellini703bc682009-08-03 10:54:05 +01002293static void vnc_refresh(void *opaque)
2294{
2295 VncDisplay *vd = opaque;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002296 VncState *vs = NULL;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002297 int has_dirty = 0, rects = 0;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002298
2299 vga_hw_update();
2300
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002301 has_dirty = vnc_refresh_server_surface(vd);
2302
2303 vs = vd->clients;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002304 while (vs != NULL) {
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002305 rects += vnc_update_client(vs, has_dirty);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002306 vs = vs->next;
2307 }
2308
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002309 if (has_dirty && rects) {
2310 vd->timer_interval /= 2;
2311 if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE)
2312 vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
2313 } else {
2314 vd->timer_interval += VNC_REFRESH_INTERVAL_INC;
2315 if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
2316 vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
2317 }
2318 qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002319}
2320
2321static void vnc_init_timer(VncDisplay *vd)
2322{
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002323 vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002324 if (vd->timer == NULL && vd->clients != NULL) {
2325 vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002326 vnc_refresh(vd);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002327 }
2328}
2329
2330static void vnc_remove_timer(VncDisplay *vd)
2331{
2332 if (vd->timer != NULL && vd->clients == NULL) {
2333 qemu_del_timer(vd->timer);
2334 qemu_free_timer(vd->timer);
2335 vd->timer = NULL;
2336 }
2337}
2338
aliguori753b4052009-02-16 14:59:30 +00002339static void vnc_connect(VncDisplay *vd, int csock)
balrog3aa3eea2008-02-03 02:54:04 +00002340{
aliguori753b4052009-02-16 14:59:30 +00002341 VncState *vs = qemu_mallocz(sizeof(VncState));
2342 vs->csock = csock;
2343
2344 VNC_DEBUG("New client on socket %d\n", csock);
aliguori7d957bd2009-01-15 22:14:11 +00002345 dcl->idle = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002346 socket_set_nonblock(vs->csock);
2347 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
aliguori753b4052009-02-16 14:59:30 +00002348
2349 vs->vd = vd;
2350 vs->ds = vd->ds;
aliguori753b4052009-02-16 14:59:30 +00002351 vs->last_x = -1;
2352 vs->last_y = -1;
2353
2354 vs->as.freq = 44100;
2355 vs->as.nchannels = 2;
2356 vs->as.fmt = AUD_FMT_S16;
2357 vs->as.endianness = 0;
2358
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002359 vs->next = vd->clients;
2360 vd->clients = vs;
2361
2362 vga_hw_update();
2363
balrog3aa3eea2008-02-03 02:54:04 +00002364 vnc_write(vs, "RFB 003.008\n", 12);
2365 vnc_flush(vs);
2366 vnc_read_when(vs, protocol_version, 12);
malc53762dd2008-12-01 20:57:52 +00002367 reset_keys(vs);
aliguori753b4052009-02-16 14:59:30 +00002368
Stefano Stabellini703bc682009-08-03 10:54:05 +01002369 vnc_init_timer(vd);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002370
Gerd Hoffmann198a0032009-06-16 14:19:48 +02002371 /* vs might be free()ed here */
balrog3aa3eea2008-02-03 02:54:04 +00002372}
2373
bellard24236862006-04-30 21:28:36 +00002374static void vnc_listen_read(void *opaque)
2375{
aliguori753b4052009-02-16 14:59:30 +00002376 VncDisplay *vs = opaque;
bellard24236862006-04-30 21:28:36 +00002377 struct sockaddr_in addr;
2378 socklen_t addrlen = sizeof(addr);
2379
balrog9f60ad52008-01-14 21:45:55 +00002380 /* Catch-up */
2381 vga_hw_update();
2382
Kevin Wolf40ff6d72009-12-02 12:24:42 +01002383 int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
aliguori753b4052009-02-16 14:59:30 +00002384 if (csock != -1) {
2385 vnc_connect(vs, csock);
bellard24236862006-04-30 21:28:36 +00002386 }
2387}
2388
ths71cab5c2007-08-25 01:35:38 +00002389void vnc_display_init(DisplayState *ds)
bellard24236862006-04-30 21:28:36 +00002390{
Stefan Weilafd32162009-05-24 22:33:34 +02002391 VncDisplay *vs = qemu_mallocz(sizeof(*vs));
bellard24236862006-04-30 21:28:36 +00002392
aliguori7d957bd2009-01-15 22:14:11 +00002393 dcl = qemu_mallocz(sizeof(DisplayChangeListener));
bellard24236862006-04-30 21:28:36 +00002394
2395 ds->opaque = vs;
aliguori7d957bd2009-01-15 22:14:11 +00002396 dcl->idle = 1;
aliguori753b4052009-02-16 14:59:30 +00002397 vnc_display = vs;
bellard24236862006-04-30 21:28:36 +00002398
2399 vs->lsock = -1;
bellard24236862006-04-30 21:28:36 +00002400
2401 vs->ds = ds;
2402
aliguori9ca313a2008-08-23 23:27:37 +00002403 if (keyboard_layout)
aliguori04837552009-03-06 20:27:10 +00002404 vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
aliguori9ca313a2008-08-23 23:27:37 +00002405 else
aliguori04837552009-03-06 20:27:10 +00002406 vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
bellard24236862006-04-30 21:28:36 +00002407
bellard24236862006-04-30 21:28:36 +00002408 if (!vs->kbd_layout)
aliguori28a76be2009-03-06 20:27:40 +00002409 exit(1);
bellard24236862006-04-30 21:28:36 +00002410
aliguori753b4052009-02-16 14:59:30 +00002411 dcl->dpy_copy = vnc_dpy_copy;
aliguori7d957bd2009-01-15 22:14:11 +00002412 dcl->dpy_update = vnc_dpy_update;
2413 dcl->dpy_resize = vnc_dpy_resize;
2414 dcl->dpy_setdata = vnc_dpy_setdata;
aliguori7d957bd2009-01-15 22:14:11 +00002415 register_displaychangelistener(ds, dcl);
ths71cab5c2007-08-25 01:35:38 +00002416}
ths73fc9742006-12-22 02:09:07 +00002417
ths6f430242007-08-25 01:39:57 +00002418
ths71cab5c2007-08-25 01:35:38 +00002419void vnc_display_close(DisplayState *ds)
2420{
aliguori753b4052009-02-16 14:59:30 +00002421 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths71cab5c2007-08-25 01:35:38 +00002422
aliguori452b4d82009-02-11 21:00:38 +00002423 if (!vs)
2424 return;
ths71cab5c2007-08-25 01:35:38 +00002425 if (vs->display) {
aliguori28a76be2009-03-06 20:27:40 +00002426 qemu_free(vs->display);
2427 vs->display = NULL;
ths71cab5c2007-08-25 01:35:38 +00002428 }
2429 if (vs->lsock != -1) {
aliguori28a76be2009-03-06 20:27:40 +00002430 qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
2431 close(vs->lsock);
2432 vs->lsock = -1;
ths71cab5c2007-08-25 01:35:38 +00002433 }
ths70848512007-08-25 01:37:05 +00002434 vs->auth = VNC_AUTH_INVALID;
blueswir1eb38c522008-09-06 17:47:39 +00002435#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002436 vs->subauth = VNC_AUTH_INVALID;
aliguori5fb6c7a2009-03-06 20:27:23 +00002437 vs->tls.x509verify = 0;
ths8d5d2d42007-08-25 01:37:51 +00002438#endif
ths71cab5c2007-08-25 01:35:38 +00002439}
2440
ths70848512007-08-25 01:37:05 +00002441int vnc_display_password(DisplayState *ds, const char *password)
2442{
aliguori753b4052009-02-16 14:59:30 +00002443 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths70848512007-08-25 01:37:05 +00002444
Zachary Amsden7ef92332009-07-30 00:15:00 -10002445 if (!vs) {
2446 return -1;
2447 }
2448
ths70848512007-08-25 01:37:05 +00002449 if (vs->password) {
aliguori28a76be2009-03-06 20:27:40 +00002450 qemu_free(vs->password);
2451 vs->password = NULL;
ths70848512007-08-25 01:37:05 +00002452 }
2453 if (password && password[0]) {
aliguori28a76be2009-03-06 20:27:40 +00002454 if (!(vs->password = qemu_strdup(password)))
2455 return -1;
Zachary Amsden52c18be2009-07-30 00:15:01 -10002456 if (vs->auth == VNC_AUTH_NONE) {
2457 vs->auth = VNC_AUTH_VNC;
2458 }
2459 } else {
2460 vs->auth = VNC_AUTH_NONE;
ths70848512007-08-25 01:37:05 +00002461 }
2462
2463 return 0;
2464}
2465
Anthony Liguorif92f8af2009-05-20 13:01:02 -05002466char *vnc_display_local_addr(DisplayState *ds)
2467{
2468 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
2469
2470 return vnc_socket_local_addr("%s:%s", vs->lsock);
2471}
2472
ths70848512007-08-25 01:37:05 +00002473int vnc_display_open(DisplayState *ds, const char *display)
ths71cab5c2007-08-25 01:35:38 +00002474{
aliguori753b4052009-02-16 14:59:30 +00002475 VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
ths70848512007-08-25 01:37:05 +00002476 const char *options;
2477 int password = 0;
balrog3aa3eea2008-02-03 02:54:04 +00002478 int reverse = 0;
aliguori9712eca2008-11-11 20:51:59 +00002479 int to_port = 0;
blueswir1eb38c522008-09-06 17:47:39 +00002480#ifdef CONFIG_VNC_TLS
ths3a702692007-08-25 01:38:36 +00002481 int tls = 0, x509 = 0;
ths8d5d2d42007-08-25 01:37:51 +00002482#endif
aliguori2f9606b2009-03-06 20:27:28 +00002483#ifdef CONFIG_VNC_SASL
2484 int sasl = 0;
2485 int saslErr;
2486#endif
aliguori76655d62009-03-06 20:27:37 +00002487 int acl = 0;
ths71cab5c2007-08-25 01:35:38 +00002488
aliguori753b4052009-02-16 14:59:30 +00002489 if (!vnc_display)
aliguori452b4d82009-02-11 21:00:38 +00002490 return -1;
ths71cab5c2007-08-25 01:35:38 +00002491 vnc_display_close(ds);
ths70848512007-08-25 01:37:05 +00002492 if (strcmp(display, "none") == 0)
aliguori28a76be2009-03-06 20:27:40 +00002493 return 0;
ths71cab5c2007-08-25 01:35:38 +00002494
ths70848512007-08-25 01:37:05 +00002495 if (!(vs->display = strdup(display)))
aliguori28a76be2009-03-06 20:27:40 +00002496 return -1;
ths70848512007-08-25 01:37:05 +00002497
2498 options = display;
2499 while ((options = strchr(options, ','))) {
aliguori28a76be2009-03-06 20:27:40 +00002500 options++;
2501 if (strncmp(options, "password", 8) == 0) {
2502 password = 1; /* Require password auth */
2503 } else if (strncmp(options, "reverse", 7) == 0) {
2504 reverse = 1;
2505 } else if (strncmp(options, "to=", 3) == 0) {
aliguori9712eca2008-11-11 20:51:59 +00002506 to_port = atoi(options+3) + 5900;
aliguori2f9606b2009-03-06 20:27:28 +00002507#ifdef CONFIG_VNC_SASL
aliguori28a76be2009-03-06 20:27:40 +00002508 } else if (strncmp(options, "sasl", 4) == 0) {
2509 sasl = 1; /* Require SASL auth */
aliguori2f9606b2009-03-06 20:27:28 +00002510#endif
blueswir1eb38c522008-09-06 17:47:39 +00002511#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002512 } else if (strncmp(options, "tls", 3) == 0) {
2513 tls = 1; /* Require TLS */
2514 } else if (strncmp(options, "x509", 4) == 0) {
2515 char *start, *end;
2516 x509 = 1; /* Require x509 certificates */
2517 if (strncmp(options, "x509verify", 10) == 0)
2518 vs->tls.x509verify = 1; /* ...and verify client certs */
ths6f430242007-08-25 01:39:57 +00002519
aliguori28a76be2009-03-06 20:27:40 +00002520 /* Now check for 'x509=/some/path' postfix
2521 * and use that to setup x509 certificate/key paths */
2522 start = strchr(options, '=');
2523 end = strchr(options, ',');
2524 if (start && (!end || (start < end))) {
2525 int len = end ? end-(start+1) : strlen(start+1);
2526 char *path = qemu_strndup(start + 1, len);
blueswir1be15b142008-10-25 11:21:28 +00002527
aliguori28a76be2009-03-06 20:27:40 +00002528 VNC_DEBUG("Trying certificate path '%s'\n", path);
2529 if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
2530 fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
2531 qemu_free(path);
2532 qemu_free(vs->display);
2533 vs->display = NULL;
2534 return -1;
2535 }
2536 qemu_free(path);
2537 } else {
2538 fprintf(stderr, "No certificate path provided\n");
2539 qemu_free(vs->display);
2540 vs->display = NULL;
2541 return -1;
2542 }
ths8d5d2d42007-08-25 01:37:51 +00002543#endif
aliguori28a76be2009-03-06 20:27:40 +00002544 } else if (strncmp(options, "acl", 3) == 0) {
2545 acl = 1;
2546 }
ths70848512007-08-25 01:37:05 +00002547 }
2548
aliguori76655d62009-03-06 20:27:37 +00002549#ifdef CONFIG_VNC_TLS
2550 if (acl && x509 && vs->tls.x509verify) {
aliguori28a76be2009-03-06 20:27:40 +00002551 if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
2552 fprintf(stderr, "Failed to create x509 dname ACL\n");
2553 exit(1);
2554 }
aliguori76655d62009-03-06 20:27:37 +00002555 }
2556#endif
2557#ifdef CONFIG_VNC_SASL
2558 if (acl && sasl) {
aliguori28a76be2009-03-06 20:27:40 +00002559 if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
2560 fprintf(stderr, "Failed to create username ACL\n");
2561 exit(1);
2562 }
aliguori76655d62009-03-06 20:27:37 +00002563 }
2564#endif
2565
aliguori2f9606b2009-03-06 20:27:28 +00002566 /*
2567 * Combinations we support here:
2568 *
2569 * - no-auth (clear text, no auth)
2570 * - password (clear text, weak auth)
2571 * - sasl (encrypt, good auth *IF* using Kerberos via GSSAPI)
2572 * - tls (encrypt, weak anonymous creds, no auth)
2573 * - tls + password (encrypt, weak anonymous creds, weak auth)
2574 * - tls + sasl (encrypt, weak anonymous creds, good auth)
2575 * - tls + x509 (encrypt, good x509 creds, no auth)
2576 * - tls + x509 + password (encrypt, good x509 creds, weak auth)
2577 * - tls + x509 + sasl (encrypt, good x509 creds, good auth)
2578 *
2579 * NB1. TLS is a stackable auth scheme.
2580 * NB2. the x509 schemes have option to validate a client cert dname
2581 */
ths70848512007-08-25 01:37:05 +00002582 if (password) {
blueswir1eb38c522008-09-06 17:47:39 +00002583#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002584 if (tls) {
2585 vs->auth = VNC_AUTH_VENCRYPT;
2586 if (x509) {
2587 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
2588 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
2589 } else {
2590 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
2591 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
2592 }
2593 } else {
aliguori2f9606b2009-03-06 20:27:28 +00002594#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00002595 VNC_DEBUG("Initializing VNC server with password auth\n");
2596 vs->auth = VNC_AUTH_VNC;
blueswir1eb38c522008-09-06 17:47:39 +00002597#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002598 vs->subauth = VNC_AUTH_INVALID;
2599 }
aliguori2f9606b2009-03-06 20:27:28 +00002600#endif /* CONFIG_VNC_TLS */
2601#ifdef CONFIG_VNC_SASL
2602 } else if (sasl) {
2603#ifdef CONFIG_VNC_TLS
2604 if (tls) {
2605 vs->auth = VNC_AUTH_VENCRYPT;
2606 if (x509) {
aliguori28a76be2009-03-06 20:27:40 +00002607 VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00002608 vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
2609 } else {
aliguori28a76be2009-03-06 20:27:40 +00002610 VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00002611 vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
2612 }
2613 } else {
2614#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00002615 VNC_DEBUG("Initializing VNC server with SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00002616 vs->auth = VNC_AUTH_SASL;
2617#ifdef CONFIG_VNC_TLS
2618 vs->subauth = VNC_AUTH_INVALID;
2619 }
2620#endif /* CONFIG_VNC_TLS */
2621#endif /* CONFIG_VNC_SASL */
ths70848512007-08-25 01:37:05 +00002622 } else {
blueswir1eb38c522008-09-06 17:47:39 +00002623#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002624 if (tls) {
2625 vs->auth = VNC_AUTH_VENCRYPT;
2626 if (x509) {
2627 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
2628 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
2629 } else {
2630 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
2631 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
2632 }
2633 } else {
ths8d5d2d42007-08-25 01:37:51 +00002634#endif
aliguori28a76be2009-03-06 20:27:40 +00002635 VNC_DEBUG("Initializing VNC server with no auth\n");
2636 vs->auth = VNC_AUTH_NONE;
blueswir1eb38c522008-09-06 17:47:39 +00002637#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00002638 vs->subauth = VNC_AUTH_INVALID;
2639 }
ths8d5d2d42007-08-25 01:37:51 +00002640#endif
ths70848512007-08-25 01:37:05 +00002641 }
bellard24236862006-04-30 21:28:36 +00002642
aliguori2f9606b2009-03-06 20:27:28 +00002643#ifdef CONFIG_VNC_SASL
2644 if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
2645 fprintf(stderr, "Failed to initialize SASL auth %s",
2646 sasl_errstring(saslErr, NULL, NULL));
2647 free(vs->display);
2648 vs->display = NULL;
2649 return -1;
2650 }
2651#endif
2652
balrog3aa3eea2008-02-03 02:54:04 +00002653 if (reverse) {
aliguori9712eca2008-11-11 20:51:59 +00002654 /* connect to viewer */
2655 if (strncmp(display, "unix:", 5) == 0)
2656 vs->lsock = unix_connect(display+5);
2657 else
2658 vs->lsock = inet_connect(display, SOCK_STREAM);
2659 if (-1 == vs->lsock) {
balrog3aa3eea2008-02-03 02:54:04 +00002660 free(vs->display);
2661 vs->display = NULL;
2662 return -1;
2663 } else {
aliguori753b4052009-02-16 14:59:30 +00002664 int csock = vs->lsock;
balrog3aa3eea2008-02-03 02:54:04 +00002665 vs->lsock = -1;
aliguori753b4052009-02-16 14:59:30 +00002666 vnc_connect(vs, csock);
balrog3aa3eea2008-02-03 02:54:04 +00002667 }
aliguori9712eca2008-11-11 20:51:59 +00002668 return 0;
balrog3aa3eea2008-02-03 02:54:04 +00002669
aliguori9712eca2008-11-11 20:51:59 +00002670 } else {
2671 /* listen for connects */
2672 char *dpy;
2673 dpy = qemu_malloc(256);
2674 if (strncmp(display, "unix:", 5) == 0) {
blueswir1bc575e92009-01-14 18:34:22 +00002675 pstrcpy(dpy, 256, "unix:");
aliguori4a55bfd2008-12-02 20:02:14 +00002676 vs->lsock = unix_listen(display+5, dpy+5, 256-5);
aliguori9712eca2008-11-11 20:51:59 +00002677 } else {
2678 vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
2679 }
2680 if (-1 == vs->lsock) {
2681 free(dpy);
balrogd0513622008-12-01 01:48:36 +00002682 return -1;
aliguori9712eca2008-11-11 20:51:59 +00002683 } else {
2684 free(vs->display);
2685 vs->display = dpy;
2686 }
bellard24236862006-04-30 21:28:36 +00002687 }
aliguori753b4052009-02-16 14:59:30 +00002688 return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00002689}