]> git.ipfire.org Git - thirdparty/qemu.git/blame - ui/vnc.c
util: move declarations out of qemu-common.h
[thirdparty/qemu.git] / ui / vnc.c
CommitLineData
7d510b8c
FB
1/*
2 * QEMU VNC display driver
5fafdf24 3 *
7d510b8c
FB
4 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5 * Copyright (C) 2006 Fabrice Bellard
19a490bf 6 * Copyright (C) 2009 Red Hat, Inc
5fafdf24 7 *
7d510b8c
FB
8 * 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
e16f4c87 27#include "qemu/osdep.h"
19a490bf 28#include "vnc.h"
bd023f95 29#include "vnc-jobs.h"
40066175 30#include "trace.h"
1d0d59fe 31#include "hw/qdev.h"
9c17d615 32#include "sysemu/sysemu.h"
d49b6836 33#include "qemu/error-report.h"
1de7afc9
PB
34#include "qemu/sockets.h"
35#include "qemu/timer.h"
36#include "qemu/acl.h"
4db14629 37#include "qemu/config-file.h"
cc7a8ea7 38#include "qapi/qmp/qerror.h"
7b1b5d19 39#include "qapi/qmp/types.h"
2b54aa87 40#include "qmp-commands.h"
8d447d10 41#include "ui/input.h"
fb6ba0d5 42#include "qapi-event.h"
8e9b0d24 43#include "crypto/hash.h"
3e305e4a
DB
44#include "crypto/tlscredsanon.h"
45#include "crypto/tlscredsx509.h"
46#include "qom/object_interfaces.h"
f348b6d1 47#include "qemu/cutils.h"
24236869 48
0f7b2864 49#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
2430ffe4 50#define VNC_REFRESH_INTERVAL_INC 50
0f7b2864 51#define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE
999342a0
CC
52static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
53static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
24236869
FB
54
55#include "vnc_keysym.h"
800567a6 56#include "crypto/cipher.h"
70848515 57
d616ccc5
GH
58static QTAILQ_HEAD(, VncDisplay) vnc_displays =
59 QTAILQ_HEAD_INITIALIZER(vnc_displays);
a9ce8590 60
d467b679 61static int vnc_cursor_define(VncState *vs);
7bc9318b 62static void vnc_release_modifiers(VncState *vs);
d467b679 63
8cf36489
GH
64static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
65{
66#ifdef _VNC_DEBUG
67 static const char *mn[] = {
68 [0] = "undefined",
69 [VNC_SHARE_MODE_CONNECTING] = "connecting",
70 [VNC_SHARE_MODE_SHARED] = "shared",
71 [VNC_SHARE_MODE_EXCLUSIVE] = "exclusive",
72 [VNC_SHARE_MODE_DISCONNECTED] = "disconnected",
73 };
04d2529d
DB
74 fprintf(stderr, "%s/%p: %s -> %s\n", __func__,
75 vs->ioc, mn[vs->share_mode], mn[mode]);
8cf36489
GH
76#endif
77
e5f34cdd
GH
78 switch (vs->share_mode) {
79 case VNC_SHARE_MODE_CONNECTING:
80 vs->vd->num_connecting--;
81 break;
82 case VNC_SHARE_MODE_SHARED:
83 vs->vd->num_shared--;
84 break;
85 case VNC_SHARE_MODE_EXCLUSIVE:
8cf36489 86 vs->vd->num_exclusive--;
e5f34cdd
GH
87 break;
88 default:
89 break;
8cf36489 90 }
e5f34cdd 91
8cf36489 92 vs->share_mode = mode;
e5f34cdd
GH
93
94 switch (vs->share_mode) {
95 case VNC_SHARE_MODE_CONNECTING:
96 vs->vd->num_connecting++;
97 break;
98 case VNC_SHARE_MODE_SHARED:
99 vs->vd->num_shared++;
100 break;
101 case VNC_SHARE_MODE_EXCLUSIVE:
8cf36489 102 vs->vd->num_exclusive++;
e5f34cdd
GH
103 break;
104 default:
105 break;
8cf36489
GH
106 }
107}
108
1ff7df1a 109
04d2529d 110static void vnc_init_basic_info(SocketAddress *addr,
98481bfc
EB
111 VncBasicInfo *info,
112 Error **errp)
d96fd29c 113{
04d2529d
DB
114 switch (addr->type) {
115 case SOCKET_ADDRESS_KIND_INET:
32bafa8f
EB
116 info->host = g_strdup(addr->u.inet.data->host);
117 info->service = g_strdup(addr->u.inet.data->port);
118 if (addr->u.inet.data->ipv6) {
04d2529d
DB
119 info->family = NETWORK_ADDRESS_FAMILY_IPV6;
120 } else {
121 info->family = NETWORK_ADDRESS_FAMILY_IPV4;
122 }
123 break;
d96fd29c 124
04d2529d
DB
125 case SOCKET_ADDRESS_KIND_UNIX:
126 info->host = g_strdup("");
32bafa8f 127 info->service = g_strdup(addr->u.q_unix.data->path);
04d2529d
DB
128 info->family = NETWORK_ADDRESS_FAMILY_UNIX;
129 break;
130
131 default:
132 error_setg(errp, "Unsupported socket kind %d",
133 addr->type);
134 break;
d96fd29c
LC
135 }
136
04d2529d 137 return;
d96fd29c
LC
138}
139
04d2529d
DB
140static void vnc_init_basic_info_from_server_addr(QIOChannelSocket *ioc,
141 VncBasicInfo *info,
98481bfc 142 Error **errp)
d96fd29c 143{
04d2529d 144 SocketAddress *addr = NULL;
d96fd29c 145
04d2529d
DB
146 addr = qio_channel_socket_get_local_address(ioc, errp);
147 if (!addr) {
98481bfc 148 return;
d96fd29c
LC
149 }
150
04d2529d
DB
151 vnc_init_basic_info(addr, info, errp);
152 qapi_free_SocketAddress(addr);
d96fd29c
LC
153}
154
04d2529d
DB
155static void vnc_init_basic_info_from_remote_addr(QIOChannelSocket *ioc,
156 VncBasicInfo *info,
98481bfc 157 Error **errp)
d96fd29c 158{
04d2529d 159 SocketAddress *addr = NULL;
d96fd29c 160
04d2529d
DB
161 addr = qio_channel_socket_get_remote_address(ioc, errp);
162 if (!addr) {
98481bfc 163 return;
d96fd29c
LC
164 }
165
04d2529d
DB
166 vnc_init_basic_info(addr, info, errp);
167 qapi_free_SocketAddress(addr);
d96fd29c
LC
168}
169
1ff7df1a
AL
170static const char *vnc_auth_name(VncDisplay *vd) {
171 switch (vd->auth) {
172 case VNC_AUTH_INVALID:
173 return "invalid";
174 case VNC_AUTH_NONE:
175 return "none";
176 case VNC_AUTH_VNC:
177 return "vnc";
178 case VNC_AUTH_RA2:
179 return "ra2";
180 case VNC_AUTH_RA2NE:
181 return "ra2ne";
182 case VNC_AUTH_TIGHT:
183 return "tight";
184 case VNC_AUTH_ULTRA:
185 return "ultra";
186 case VNC_AUTH_TLS:
187 return "tls";
188 case VNC_AUTH_VENCRYPT:
1ff7df1a
AL
189 switch (vd->subauth) {
190 case VNC_AUTH_VENCRYPT_PLAIN:
191 return "vencrypt+plain";
192 case VNC_AUTH_VENCRYPT_TLSNONE:
193 return "vencrypt+tls+none";
194 case VNC_AUTH_VENCRYPT_TLSVNC:
195 return "vencrypt+tls+vnc";
196 case VNC_AUTH_VENCRYPT_TLSPLAIN:
197 return "vencrypt+tls+plain";
198 case VNC_AUTH_VENCRYPT_X509NONE:
199 return "vencrypt+x509+none";
200 case VNC_AUTH_VENCRYPT_X509VNC:
201 return "vencrypt+x509+vnc";
202 case VNC_AUTH_VENCRYPT_X509PLAIN:
203 return "vencrypt+x509+plain";
28a76be8
AL
204 case VNC_AUTH_VENCRYPT_TLSSASL:
205 return "vencrypt+tls+sasl";
206 case VNC_AUTH_VENCRYPT_X509SASL:
207 return "vencrypt+x509+sasl";
1ff7df1a
AL
208 default:
209 return "vencrypt";
210 }
2f9606b3 211 case VNC_AUTH_SASL:
28a76be8 212 return "sasl";
1ff7df1a
AL
213 }
214 return "unknown";
215}
216
d616ccc5 217static VncServerInfo *vnc_server_info_get(VncDisplay *vd)
a7789382 218{
fb6ba0d5 219 VncServerInfo *info;
98481bfc 220 Error *err = NULL;
a7789382 221
fb6ba0d5 222 info = g_malloc(sizeof(*info));
ddf21908
EB
223 vnc_init_basic_info_from_server_addr(vd->lsock,
224 qapi_VncServerInfo_base(info), &err);
fb6ba0d5 225 info->has_auth = true;
d616ccc5 226 info->auth = g_strdup(vnc_auth_name(vd));
98481bfc
EB
227 if (err) {
228 qapi_free_VncServerInfo(info);
229 info = NULL;
230 error_free(err);
231 }
fb6ba0d5 232 return info;
a7789382
LC
233}
234
4a80dba3 235static void vnc_client_cache_auth(VncState *client)
1ff7df1a 236{
4a80dba3
LC
237 if (!client->info) {
238 return;
d96fd29c 239 }
1263b7d6 240
3e305e4a
DB
241 if (client->tls) {
242 client->info->x509_dname =
243 qcrypto_tls_session_get_peer_name(client->tls);
244 client->info->has_x509_dname =
245 client->info->x509_dname != NULL;
d96fd29c 246 }
1263b7d6
AL
247#ifdef CONFIG_VNC_SASL
248 if (client->sasl.conn &&
d96fd29c 249 client->sasl.username) {
fb6ba0d5
WX
250 client->info->has_sasl_username = true;
251 client->info->sasl_username = g_strdup(client->sasl.username);
d96fd29c 252 }
1263b7d6 253#endif
4a80dba3 254}
d96fd29c 255
4a80dba3
LC
256static void vnc_client_cache_addr(VncState *client)
257{
98481bfc
EB
258 Error *err = NULL;
259
260 client->info = g_malloc0(sizeof(*client->info));
04d2529d 261 vnc_init_basic_info_from_remote_addr(client->sioc,
ddf21908 262 qapi_VncClientInfo_base(client->info),
98481bfc
EB
263 &err);
264 if (err) {
265 qapi_free_VncClientInfo(client->info);
266 client->info = NULL;
267 error_free(err);
4a80dba3 268 }
1ff7df1a
AL
269}
270
fb6ba0d5 271static void vnc_qmp_event(VncState *vs, QAPIEvent event)
586153d9 272{
fb6ba0d5 273 VncServerInfo *si;
586153d9
LC
274
275 if (!vs->info) {
276 return;
277 }
278
d616ccc5 279 si = vnc_server_info_get(vs->vd);
fb6ba0d5 280 if (!si) {
586153d9
LC
281 return;
282 }
283
fb6ba0d5
WX
284 switch (event) {
285 case QAPI_EVENT_VNC_CONNECTED:
ddf21908
EB
286 qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info),
287 &error_abort);
fb6ba0d5
WX
288 break;
289 case QAPI_EVENT_VNC_INITIALIZED:
290 qapi_event_send_vnc_initialized(si, vs->info, &error_abort);
291 break;
292 case QAPI_EVENT_VNC_DISCONNECTED:
293 qapi_event_send_vnc_disconnected(si, vs->info, &error_abort);
294 break;
295 default:
296 break;
297 }
586153d9 298
fb6ba0d5 299 qapi_free_VncServerInfo(si);
586153d9
LC
300}
301
2b54aa87 302static VncClientInfo *qmp_query_vnc_client(const VncState *client)
a9ce8590 303{
2b54aa87 304 VncClientInfo *info;
04d2529d 305 Error *err = NULL;
2b54aa87 306
04d2529d 307 info = g_malloc0(sizeof(*info));
2b54aa87 308
04d2529d
DB
309 vnc_init_basic_info_from_remote_addr(client->sioc,
310 qapi_VncClientInfo_base(info),
311 &err);
312 if (err) {
313 error_free(err);
314 qapi_free_VncClientInfo(info);
2b54aa87
LC
315 return NULL;
316 }
d96fd29c 317
ddf21908 318 info->websocket = client->websocket;
d96fd29c 319
3e305e4a
DB
320 if (client->tls) {
321 info->x509_dname = qcrypto_tls_session_get_peer_name(client->tls);
322 info->has_x509_dname = info->x509_dname != NULL;
2b54aa87 323 }
d96fd29c 324#ifdef CONFIG_VNC_SASL
2b54aa87
LC
325 if (client->sasl.conn && client->sasl.username) {
326 info->has_sasl_username = true;
327 info->sasl_username = g_strdup(client->sasl.username);
d96fd29c 328 }
2b54aa87 329#endif
1ff7df1a 330
2b54aa87 331 return info;
d96fd29c 332}
1ff7df1a 333
d616ccc5
GH
334static VncDisplay *vnc_display_find(const char *id)
335{
336 VncDisplay *vd;
337
338 if (id == NULL) {
339 return QTAILQ_FIRST(&vnc_displays);
340 }
341 QTAILQ_FOREACH(vd, &vnc_displays, next) {
342 if (strcmp(id, vd->id) == 0) {
343 return vd;
344 }
345 }
346 return NULL;
347}
348
2d29a436
GH
349static VncClientInfoList *qmp_query_client_list(VncDisplay *vd)
350{
351 VncClientInfoList *cinfo, *prev = NULL;
352 VncState *client;
353
354 QTAILQ_FOREACH(client, &vd->clients, next) {
355 cinfo = g_new0(VncClientInfoList, 1);
356 cinfo->value = qmp_query_vnc_client(client);
357 cinfo->next = prev;
358 prev = cinfo;
359 }
360 return prev;
361}
362
2b54aa87 363VncInfo *qmp_query_vnc(Error **errp)
d96fd29c 364{
2b54aa87 365 VncInfo *info = g_malloc0(sizeof(*info));
d616ccc5 366 VncDisplay *vd = vnc_display_find(NULL);
04d2529d 367 SocketAddress *addr = NULL;
2b54aa87 368
bf7aa45e 369 if (vd == NULL || !vd->enabled) {
2b54aa87 370 info->enabled = false;
d96fd29c 371 } else {
2b54aa87
LC
372 info->enabled = true;
373
374 /* for compatibility with the original command */
375 info->has_clients = true;
2d29a436 376 info->clients = qmp_query_client_list(vd);
d96fd29c 377
04d2529d 378 if (vd->lsock == NULL) {
417b0b88
PB
379 return info;
380 }
381
04d2529d
DB
382 addr = qio_channel_socket_get_local_address(vd->lsock, errp);
383 if (!addr) {
2b54aa87
LC
384 goto out_error;
385 }
d96fd29c 386
04d2529d
DB
387 switch (addr->type) {
388 case SOCKET_ADDRESS_KIND_INET:
32bafa8f
EB
389 info->host = g_strdup(addr->u.inet.data->host);
390 info->service = g_strdup(addr->u.inet.data->port);
391 if (addr->u.inet.data->ipv6) {
04d2529d
DB
392 info->family = NETWORK_ADDRESS_FAMILY_IPV6;
393 } else {
394 info->family = NETWORK_ADDRESS_FAMILY_IPV4;
395 }
396 break;
397
398 case SOCKET_ADDRESS_KIND_UNIX:
399 info->host = g_strdup("");
32bafa8f 400 info->service = g_strdup(addr->u.q_unix.data->path);
04d2529d
DB
401 info->family = NETWORK_ADDRESS_FAMILY_UNIX;
402 break;
403
404 default:
405 error_setg(errp, "Unsupported socket kind %d",
406 addr->type);
2b54aa87 407 goto out_error;
1ff7df1a 408 }
2b54aa87
LC
409
410 info->has_host = true;
2b54aa87 411 info->has_service = true;
2b54aa87 412 info->has_family = true;
2b54aa87
LC
413
414 info->has_auth = true;
d616ccc5 415 info->auth = g_strdup(vnc_auth_name(vd));
a9ce8590 416 }
2b54aa87 417
04d2529d 418 qapi_free_SocketAddress(addr);
2b54aa87
LC
419 return info;
420
421out_error:
04d2529d 422 qapi_free_SocketAddress(addr);
2b54aa87
LC
423 qapi_free_VncInfo(info);
424 return NULL;
a9ce8590
FB
425}
426
04d2529d 427static VncBasicInfoList *qmp_query_server_entry(QIOChannelSocket *ioc,
4478aa76 428 bool websocket,
df887684
GH
429 VncBasicInfoList *prev)
430{
431 VncBasicInfoList *list;
432 VncBasicInfo *info;
04d2529d
DB
433 Error *err = NULL;
434 SocketAddress *addr;
435
436 addr = qio_channel_socket_get_local_address(ioc, &err);
437 if (!addr) {
438 error_free(err);
df887684
GH
439 return prev;
440 }
441
442 info = g_new0(VncBasicInfo, 1);
04d2529d
DB
443 vnc_init_basic_info(addr, info, &err);
444 qapi_free_SocketAddress(addr);
445 if (err) {
446 qapi_free_VncBasicInfo(info);
447 error_free(err);
448 return prev;
449 }
4478aa76 450 info->websocket = websocket;
df887684
GH
451
452 list = g_new0(VncBasicInfoList, 1);
453 list->value = info;
454 list->next = prev;
455 return list;
456}
457
458static void qmp_query_auth(VncDisplay *vd, VncInfo2 *info)
459{
460 switch (vd->auth) {
461 case VNC_AUTH_VNC:
462 info->auth = VNC_PRIMARY_AUTH_VNC;
463 break;
464 case VNC_AUTH_RA2:
465 info->auth = VNC_PRIMARY_AUTH_RA2;
466 break;
467 case VNC_AUTH_RA2NE:
468 info->auth = VNC_PRIMARY_AUTH_RA2NE;
469 break;
470 case VNC_AUTH_TIGHT:
471 info->auth = VNC_PRIMARY_AUTH_TIGHT;
472 break;
473 case VNC_AUTH_ULTRA:
474 info->auth = VNC_PRIMARY_AUTH_ULTRA;
475 break;
476 case VNC_AUTH_TLS:
477 info->auth = VNC_PRIMARY_AUTH_TLS;
478 break;
479 case VNC_AUTH_VENCRYPT:
480 info->auth = VNC_PRIMARY_AUTH_VENCRYPT;
df887684
GH
481 info->has_vencrypt = true;
482 switch (vd->subauth) {
483 case VNC_AUTH_VENCRYPT_PLAIN:
484 info->vencrypt = VNC_VENCRYPT_SUB_AUTH_PLAIN;
485 break;
486 case VNC_AUTH_VENCRYPT_TLSNONE:
487 info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_NONE;
488 break;
489 case VNC_AUTH_VENCRYPT_TLSVNC:
490 info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_VNC;
491 break;
492 case VNC_AUTH_VENCRYPT_TLSPLAIN:
493 info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_PLAIN;
494 break;
495 case VNC_AUTH_VENCRYPT_X509NONE:
496 info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_NONE;
497 break;
498 case VNC_AUTH_VENCRYPT_X509VNC:
499 info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_VNC;
500 break;
501 case VNC_AUTH_VENCRYPT_X509PLAIN:
502 info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_PLAIN;
503 break;
504 case VNC_AUTH_VENCRYPT_TLSSASL:
505 info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_SASL;
506 break;
507 case VNC_AUTH_VENCRYPT_X509SASL:
508 info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_SASL;
509 break;
510 default:
511 info->has_vencrypt = false;
512 break;
513 }
df887684
GH
514 break;
515 case VNC_AUTH_SASL:
516 info->auth = VNC_PRIMARY_AUTH_SASL;
517 break;
518 case VNC_AUTH_NONE:
519 default:
520 info->auth = VNC_PRIMARY_AUTH_NONE;
521 break;
522 }
523}
524
525VncInfo2List *qmp_query_vnc_servers(Error **errp)
526{
527 VncInfo2List *item, *prev = NULL;
528 VncInfo2 *info;
529 VncDisplay *vd;
530 DeviceState *dev;
531
532 QTAILQ_FOREACH(vd, &vnc_displays, next) {
533 info = g_new0(VncInfo2, 1);
534 info->id = g_strdup(vd->id);
535 info->clients = qmp_query_client_list(vd);
536 qmp_query_auth(vd, info);
537 if (vd->dcl.con) {
538 dev = DEVICE(object_property_get_link(OBJECT(vd->dcl.con),
539 "device", NULL));
540 info->has_display = true;
541 info->display = g_strdup(dev->id);
542 }
04d2529d
DB
543 if (vd->lsock != NULL) {
544 info->server = qmp_query_server_entry(
545 vd->lsock, false, info->server);
df887684 546 }
04d2529d
DB
547 if (vd->lwebsock != NULL) {
548 info->server = qmp_query_server_entry(
549 vd->lwebsock, true, info->server);
df887684 550 }
df887684
GH
551
552 item = g_new0(VncInfo2List, 1);
553 item->value = info;
554 item->next = prev;
555 prev = item;
556 }
557 return prev;
558}
559
24236869
FB
560/* TODO
561 1) Get the queue working for IO.
562 2) there is some weirdness when using the -S option (the screen is grey
563 and not totally invalidated
564 3) resolutions > 1024
565*/
566
38ee14f4 567static int vnc_update_client(VncState *vs, int has_dirty, bool sync);
198a0039 568static void vnc_disconnect_start(VncState *vs);
24236869 569
753b4053 570static void vnc_colordepth(VncState *vs);
1fc62412
SS
571static void framebuffer_update_request(VncState *vs, int incremental,
572 int x_position, int y_position,
573 int w, int h);
0f7b2864 574static void vnc_refresh(DisplayChangeListener *dcl);
1fc62412 575static int vnc_refresh_server_surface(VncDisplay *vd);
7eac3a87 576
d05959c2
GH
577static int vnc_width(VncDisplay *vd)
578{
579 return MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
580 VNC_DIRTY_PIXELS_PER_BIT));
581}
582
583static int vnc_height(VncDisplay *vd)
584{
585 return MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
586}
587
bea60dd7
PL
588static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
589 VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT),
f7b3d68c
GH
590 VncDisplay *vd,
591 int x, int y, int w, int h)
592{
593 int width = vnc_width(vd);
594 int height = vnc_height(vd);
595
91937225
PL
596 /* this is needed this to ensure we updated all affected
597 * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
b4c85ddc
PL
598 w += (x % VNC_DIRTY_PIXELS_PER_BIT);
599 x -= (x % VNC_DIRTY_PIXELS_PER_BIT);
0486e8a7 600
9f64916d
GH
601 x = MIN(x, width);
602 y = MIN(y, height);
603 w = MIN(x + w, width) - x;
91937225 604 h = MIN(y + h, height);
788abf8e 605
b4c85ddc 606 for (; y < h; y++) {
bea60dd7 607 bitmap_set(dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
91937225 608 DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
b4c85ddc 609 }
24236869
FB
610}
611
bea60dd7
PL
612static void vnc_dpy_update(DisplayChangeListener *dcl,
613 int x, int y, int w, int h)
614{
615 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
616 struct VncSurface *s = &vd->guest;
bea60dd7 617
f7b3d68c 618 vnc_set_area_dirty(s->dirty, vd, x, y, w, h);
bea60dd7
PL
619}
620
70a4568f
CC
621void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
622 int32_t encoding)
24236869
FB
623{
624 vnc_write_u16(vs, x);
625 vnc_write_u16(vs, y);
626 vnc_write_u16(vs, w);
627 vnc_write_u16(vs, h);
628
629 vnc_write_s32(vs, encoding);
630}
631
32ed2680 632
621aaeb9
GH
633static void vnc_desktop_resize(VncState *vs)
634{
04d2529d 635 if (vs->ioc == NULL || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
621aaeb9
GH
636 return;
637 }
bea60dd7
PL
638 if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
639 vs->client_height == pixman_image_get_height(vs->vd->server)) {
1d4b638a
GH
640 return;
641 }
bea60dd7
PL
642 vs->client_width = pixman_image_get_width(vs->vd->server);
643 vs->client_height = pixman_image_get_height(vs->vd->server);
bd023f95 644 vnc_lock_output(vs);
621aaeb9
GH
645 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
646 vnc_write_u8(vs, 0);
647 vnc_write_u16(vs, 1); /* number of rects */
5862d195 648 vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
621aaeb9 649 VNC_ENCODING_DESKTOPRESIZE);
bd023f95 650 vnc_unlock_output(vs);
621aaeb9
GH
651 vnc_flush(vs);
652}
653
bd023f95
CC
654static void vnc_abort_display_jobs(VncDisplay *vd)
655{
656 VncState *vs;
657
658 QTAILQ_FOREACH(vs, &vd->clients, next) {
659 vnc_lock_output(vs);
660 vs->abort = true;
661 vnc_unlock_output(vs);
662 }
663 QTAILQ_FOREACH(vs, &vd->clients, next) {
664 vnc_jobs_join(vs);
665 }
666 QTAILQ_FOREACH(vs, &vd->clients, next) {
667 vnc_lock_output(vs);
668 vs->abort = false;
669 vnc_unlock_output(vs);
670 }
671}
bd023f95 672
9f64916d
GH
673int vnc_server_fb_stride(VncDisplay *vd)
674{
675 return pixman_image_get_stride(vd->server);
676}
677
678void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
679{
680 uint8_t *ptr;
681
682 ptr = (uint8_t *)pixman_image_get_data(vd->server);
683 ptr += y * vnc_server_fb_stride(vd);
684 ptr += x * VNC_SERVER_FB_BYTES;
685 return ptr;
686}
687
453f842b
GH
688static void vnc_update_server_surface(VncDisplay *vd)
689{
690 qemu_pixman_image_unref(vd->server);
691 vd->server = NULL;
692
c7628bff
GH
693 if (QTAILQ_EMPTY(&vd->clients)) {
694 return;
695 }
696
453f842b
GH
697 vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
698 vnc_width(vd),
699 vnc_height(vd),
700 NULL, 0);
701}
702
c12aeb86 703static void vnc_dpy_switch(DisplayChangeListener *dcl,
c12aeb86 704 DisplaySurface *surface)
24236869 705{
21ef45d7 706 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
41b4bef6 707 VncState *vs;
bea60dd7 708 int width, height;
1fc62412 709
bd023f95 710 vnc_abort_display_jobs(vd);
453f842b 711 vd->ds = surface;
bd023f95 712
1fc62412 713 /* server surface */
453f842b 714 vnc_update_server_surface(vd);
24236869 715
6baebed7 716 /* guest surface */
9f64916d 717 qemu_pixman_image_unref(vd->guest.fb);
d39fa6d8
GH
718 vd->guest.fb = pixman_image_ref(surface->image);
719 vd->guest.format = surface->format;
453f842b
GH
720 width = vnc_width(vd);
721 height = vnc_height(vd);
bea60dd7 722 memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty));
f7b3d68c 723 vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0,
bea60dd7 724 width, height);
24236869 725
41b4bef6 726 QTAILQ_FOREACH(vs, &vd->clients, next) {
1fc62412 727 vnc_colordepth(vs);
1d4b638a 728 vnc_desktop_resize(vs);
d467b679
GH
729 if (vs->vd->cursor) {
730 vnc_cursor_define(vs);
731 }
bea60dd7 732 memset(vs->dirty, 0x00, sizeof(vs->dirty));
f7b3d68c 733 vnc_set_area_dirty(vs->dirty, vd, 0, 0,
bea60dd7 734 width, height);
753b4053
AL
735 }
736}
737
3512779a 738/* fastest code */
9f64916d 739static void vnc_write_pixels_copy(VncState *vs,
d467b679 740 void *pixels, int size)
3512779a
FB
741{
742 vnc_write(vs, pixels, size);
743}
744
745/* slowest but generic code. */
70a4568f 746void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
3512779a 747{
7eac3a87 748 uint8_t r, g, b;
1fc62412 749
9f64916d
GH
750#if VNC_SERVER_FB_FORMAT == PIXMAN_FORMAT(32, PIXMAN_TYPE_ARGB, 0, 8, 8, 8)
751 r = (((v & 0x00ff0000) >> 16) << vs->client_pf.rbits) >> 8;
752 g = (((v & 0x0000ff00) >> 8) << vs->client_pf.gbits) >> 8;
753 b = (((v & 0x000000ff) >> 0) << vs->client_pf.bbits) >> 8;
754#else
755# error need some bits here if you change VNC_SERVER_FB_FORMAT
756#endif
757 v = (r << vs->client_pf.rshift) |
758 (g << vs->client_pf.gshift) |
759 (b << vs->client_pf.bshift);
760 switch (vs->client_pf.bytes_per_pixel) {
3512779a
FB
761 case 1:
762 buf[0] = v;
763 break;
764 case 2:
9f64916d 765 if (vs->client_be) {
3512779a
FB
766 buf[0] = v >> 8;
767 buf[1] = v;
768 } else {
769 buf[1] = v >> 8;
770 buf[0] = v;
771 }
772 break;
773 default:
774 case 4:
9f64916d 775 if (vs->client_be) {
3512779a
FB
776 buf[0] = v >> 24;
777 buf[1] = v >> 16;
778 buf[2] = v >> 8;
779 buf[3] = v;
780 } else {
781 buf[3] = v >> 24;
782 buf[2] = v >> 16;
783 buf[1] = v >> 8;
784 buf[0] = v;
785 }
786 break;
787 }
788}
789
9f64916d 790static void vnc_write_pixels_generic(VncState *vs,
d467b679 791 void *pixels1, int size)
3512779a 792{
3512779a 793 uint8_t buf[4];
3512779a 794
9f64916d 795 if (VNC_SERVER_FB_BYTES == 4) {
7eac3a87
AL
796 uint32_t *pixels = pixels1;
797 int n, i;
798 n = size >> 2;
9f64916d 799 for (i = 0; i < n; i++) {
7eac3a87 800 vnc_convert_pixel(vs, buf, pixels[i]);
9f64916d 801 vnc_write(vs, buf, vs->client_pf.bytes_per_pixel);
7eac3a87 802 }
3512779a
FB
803 }
804}
805
a885211e 806int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
24236869
FB
807{
808 int i;
60fe76f3 809 uint8_t *row;
1fc62412 810 VncDisplay *vd = vs->vd;
24236869 811
9f64916d 812 row = vnc_server_fb_ptr(vd, x, y);
24236869 813 for (i = 0; i < h; i++) {
9f64916d
GH
814 vs->write_pixels(vs, row, w * VNC_SERVER_FB_BYTES);
815 row += vnc_server_fb_stride(vd);
24236869 816 }
a885211e 817 return 1;
24236869
FB
818}
819
bd023f95 820int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
24236869 821{
a885211e 822 int n = 0;
de3f7de7
PL
823 bool encode_raw = false;
824 size_t saved_offs = vs->output.offset;
a885211e 825
fb437313 826 switch(vs->vnc_encoding) {
28a76be8 827 case VNC_ENCODING_ZLIB:
a885211e 828 n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
28a76be8
AL
829 break;
830 case VNC_ENCODING_HEXTILE:
831 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
a885211e 832 n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
28a76be8 833 break;
380282b0
CC
834 case VNC_ENCODING_TIGHT:
835 n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
836 break;
efe556ad
CC
837 case VNC_ENCODING_TIGHT_PNG:
838 n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
839 break;
148954fa
CC
840 case VNC_ENCODING_ZRLE:
841 n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
842 break;
843 case VNC_ENCODING_ZYWRLE:
844 n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
845 break;
28a76be8 846 default:
de3f7de7 847 encode_raw = true;
28a76be8 848 break;
fb437313 849 }
de3f7de7
PL
850
851 /* If the client has the same pixel format as our internal buffer and
852 * a RAW encoding would need less space fall back to RAW encoding to
853 * save bandwidth and processing power in the client. */
854 if (!encode_raw && vs->write_pixels == vnc_write_pixels_copy &&
855 12 + h * w * VNC_SERVER_FB_BYTES <= (vs->output.offset - saved_offs)) {
856 vs->output.offset = saved_offs;
857 encode_raw = true;
858 }
859
860 if (encode_raw) {
861 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
862 n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
863 }
864
a885211e 865 return n;
24236869
FB
866}
867
753b4053 868static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
24236869 869{
3e28c9ad 870 /* send bitblit op to the vnc client */
bd023f95 871 vnc_lock_output(vs);
46a183da 872 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
24236869
FB
873 vnc_write_u8(vs, 0);
874 vnc_write_u16(vs, 1); /* number of rects */
29fa4ed9 875 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
24236869
FB
876 vnc_write_u16(vs, src_x);
877 vnc_write_u16(vs, src_y);
bd023f95 878 vnc_unlock_output(vs);
24236869
FB
879 vnc_flush(vs);
880}
881
7c20b4a3 882static void vnc_dpy_copy(DisplayChangeListener *dcl,
7c20b4a3
GH
883 int src_x, int src_y,
884 int dst_x, int dst_y, int w, int h)
753b4053 885{
21ef45d7 886 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
198a0039 887 VncState *vs, *vn;
1fc62412
SS
888 uint8_t *src_row;
889 uint8_t *dst_row;
9f64916d 890 int i, x, y, pitch, inc, w_lim, s;
1fc62412 891 int cmp_bytes;
198a0039 892
7fe4a41c
GH
893 if (!vd->server) {
894 /* no client connected */
895 return;
896 }
897
1fc62412 898 vnc_refresh_server_surface(vd);
41b4bef6 899 QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
198a0039
GH
900 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
901 vs->force_update = 1;
38ee14f4 902 vnc_update_client(vs, 1, true);
198a0039
GH
903 /* vs might be free()ed here */
904 }
905 }
906
1fc62412 907 /* do bitblit op on the local surface too */
9f64916d
GH
908 pitch = vnc_server_fb_stride(vd);
909 src_row = vnc_server_fb_ptr(vd, src_x, src_y);
910 dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y);
1fc62412
SS
911 y = dst_y;
912 inc = 1;
913 if (dst_y > src_y) {
914 /* copy backwards */
915 src_row += pitch * (h-1);
916 dst_row += pitch * (h-1);
917 pitch = -pitch;
918 y = dst_y + h - 1;
919 inc = -1;
920 }
b4c85ddc
PL
921 w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
922 if (w_lim < 0) {
1fc62412 923 w_lim = w;
b4c85ddc
PL
924 } else {
925 w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT);
926 }
1fc62412
SS
927 for (i = 0; i < h; i++) {
928 for (x = 0; x <= w_lim;
929 x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
930 if (x == w_lim) {
931 if ((s = w - w_lim) == 0)
932 break;
933 } else if (!x) {
b4c85ddc
PL
934 s = (VNC_DIRTY_PIXELS_PER_BIT -
935 (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
1fc62412
SS
936 s = MIN(s, w_lim);
937 } else {
b4c85ddc 938 s = VNC_DIRTY_PIXELS_PER_BIT;
1fc62412 939 }
9f64916d 940 cmp_bytes = s * VNC_SERVER_FB_BYTES;
1fc62412
SS
941 if (memcmp(src_row, dst_row, cmp_bytes) == 0)
942 continue;
943 memmove(dst_row, src_row, cmp_bytes);
41b4bef6
AS
944 QTAILQ_FOREACH(vs, &vd->clients, next) {
945 if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
b4c85ddc
PL
946 set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT),
947 vs->dirty[y]);
41b4bef6 948 }
1fc62412
SS
949 }
950 }
9f64916d
GH
951 src_row += pitch - w * VNC_SERVER_FB_BYTES;
952 dst_row += pitch - w * VNC_SERVER_FB_BYTES;
1fc62412
SS
953 y += inc;
954 }
955
41b4bef6
AS
956 QTAILQ_FOREACH(vs, &vd->clients, next) {
957 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
753b4053 958 vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
41b4bef6 959 }
753b4053
AL
960 }
961}
962
7c20b4a3 963static void vnc_mouse_set(DisplayChangeListener *dcl,
7c20b4a3 964 int x, int y, int visible)
d467b679
GH
965{
966 /* can we ask the client(s) to move the pointer ??? */
967}
968
969static int vnc_cursor_define(VncState *vs)
970{
971 QEMUCursor *c = vs->vd->cursor;
d467b679
GH
972 int isize;
973
974 if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
d01f9595 975 vnc_lock_output(vs);
d467b679
GH
976 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
977 vnc_write_u8(vs, 0); /* padding */
978 vnc_write_u16(vs, 1); /* # of rects */
979 vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
980 VNC_ENCODING_RICH_CURSOR);
9f64916d
GH
981 isize = c->width * c->height * vs->client_pf.bytes_per_pixel;
982 vnc_write_pixels_generic(vs, c->data, isize);
d467b679 983 vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
d01f9595 984 vnc_unlock_output(vs);
d467b679
GH
985 return 0;
986 }
987 return -1;
988}
989
7c20b4a3 990static void vnc_dpy_cursor_define(DisplayChangeListener *dcl,
7c20b4a3 991 QEMUCursor *c)
d467b679 992{
d616ccc5 993 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
d467b679
GH
994 VncState *vs;
995
996 cursor_put(vd->cursor);
7267c094 997 g_free(vd->cursor_mask);
d467b679
GH
998
999 vd->cursor = c;
1000 cursor_get(vd->cursor);
1001 vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
7267c094 1002 vd->cursor_mask = g_malloc0(vd->cursor_msize);
d467b679
GH
1003 cursor_get_mono_mask(c, 0, vd->cursor_mask);
1004
1005 QTAILQ_FOREACH(vs, &vd->clients, next) {
1006 vnc_cursor_define(vs);
1007 }
1008}
1009
4769a881 1010static int find_and_clear_dirty_height(VncState *vs,
6c71a539 1011 int y, int last_x, int x, int height)
24236869
FB
1012{
1013 int h;
1014
6c71a539 1015 for (h = 1; h < (height - y); h++) {
bc2429b9 1016 if (!test_bit(last_x, vs->dirty[y + h])) {
28a76be8 1017 break;
bc2429b9 1018 }
863d7c91 1019 bitmap_clear(vs->dirty[y + h], last_x, x - last_x);
24236869
FB
1020 }
1021
1022 return h;
1023}
1024
38ee14f4 1025static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
24236869 1026{
63658280 1027 vs->has_dirty += has_dirty;
04d2529d 1028 if (vs->need_update && vs->ioc != NULL) {
1fc62412 1029 VncDisplay *vd = vs->vd;
bd023f95 1030 VncJob *job;
28a76be8 1031 int y;
2f487a3d 1032 int height, width;
bd023f95
CC
1033 int n = 0;
1034
703bc68f 1035 if (vs->output.offset && !vs->audio_cap && !vs->force_update)
c522d0e2 1036 /* kernel send buffers are full -> drop frames to throttle */
2430ffe4 1037 return 0;
a0ecfb73 1038
63658280 1039 if (!vs->has_dirty && !vs->audio_cap && !vs->force_update)
2430ffe4 1040 return 0;
28a76be8 1041
6baebed7
AL
1042 /*
1043 * Send screen updates to the vnc client using the server
1044 * surface and server dirty map. guest surface updates
1045 * happening in parallel don't disturb us, the next pass will
1046 * send them to the client.
1047 */
bd023f95 1048 job = vnc_job_new(vs);
28a76be8 1049
bea60dd7
PL
1050 height = pixman_image_get_height(vd->server);
1051 width = pixman_image_get_width(vd->server);
847ce6a1 1052
12b316d4
PL
1053 y = 0;
1054 for (;;) {
1055 int x, h;
1056 unsigned long x2;
1057 unsigned long offset = find_next_bit((unsigned long *) &vs->dirty,
1058 height * VNC_DIRTY_BPL(vs),
1059 y * VNC_DIRTY_BPL(vs));
1060 if (offset == height * VNC_DIRTY_BPL(vs)) {
1061 /* no more dirty bits */
1062 break;
28a76be8 1063 }
12b316d4
PL
1064 y = offset / VNC_DIRTY_BPL(vs);
1065 x = offset % VNC_DIRTY_BPL(vs);
1066 x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y],
1067 VNC_DIRTY_BPL(vs), x);
1068 bitmap_clear(vs->dirty[y], x, x2 - x);
1069 h = find_and_clear_dirty_height(vs, y, x, x2, height);
2f487a3d
PL
1070 x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT);
1071 if (x2 > x) {
1072 n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y,
1073 (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h);
1074 }
0e7d6f60
PL
1075 if (!x && x2 == width / VNC_DIRTY_PIXELS_PER_BIT) {
1076 y += h;
1077 if (y == height) {
1078 break;
1079 }
1080 }
28a76be8 1081 }
bd023f95
CC
1082
1083 vnc_job_push(job);
eb214ff8
GH
1084 if (sync) {
1085 vnc_jobs_join(vs);
1086 }
c522d0e2 1087 vs->force_update = 0;
63658280 1088 vs->has_dirty = 0;
bd023f95 1089 return n;
24236869 1090 }
24236869 1091
04d2529d 1092 if (vs->disconnecting) {
198a0039 1093 vnc_disconnect_finish(vs);
38ee14f4
GH
1094 } else if (sync) {
1095 vnc_jobs_join(vs);
1096 }
2430ffe4
SS
1097
1098 return 0;
24236869
FB
1099}
1100
429a8ed3 1101/* audio */
1102static void audio_capture_notify(void *opaque, audcnotification_e cmd)
1103{
1104 VncState *vs = opaque;
1105
1106 switch (cmd) {
1107 case AUD_CNOTIFY_DISABLE:
bd023f95 1108 vnc_lock_output(vs);
46a183da
DB
1109 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
1110 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
1111 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
bd023f95 1112 vnc_unlock_output(vs);
429a8ed3 1113 vnc_flush(vs);
1114 break;
1115
1116 case AUD_CNOTIFY_ENABLE:
bd023f95 1117 vnc_lock_output(vs);
46a183da
DB
1118 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
1119 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
1120 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
bd023f95 1121 vnc_unlock_output(vs);
429a8ed3 1122 vnc_flush(vs);
1123 break;
1124 }
1125}
1126
1127static void audio_capture_destroy(void *opaque)
1128{
1129}
1130
1131static void audio_capture(void *opaque, void *buf, int size)
1132{
1133 VncState *vs = opaque;
1134
bd023f95 1135 vnc_lock_output(vs);
46a183da
DB
1136 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
1137 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
1138 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
429a8ed3 1139 vnc_write_u32(vs, size);
1140 vnc_write(vs, buf, size);
bd023f95 1141 vnc_unlock_output(vs);
429a8ed3 1142 vnc_flush(vs);
1143}
1144
1145static void audio_add(VncState *vs)
1146{
1147 struct audio_capture_ops ops;
1148
1149 if (vs->audio_cap) {
027a79c3 1150 error_report("audio already running");
429a8ed3 1151 return;
1152 }
1153
1154 ops.notify = audio_capture_notify;
1155 ops.destroy = audio_capture_destroy;
1156 ops.capture = audio_capture;
1157
1a7dafce 1158 vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
429a8ed3 1159 if (!vs->audio_cap) {
027a79c3 1160 error_report("Failed to add audio capture");
429a8ed3 1161 }
1162}
1163
1164static void audio_del(VncState *vs)
1165{
1166 if (vs->audio_cap) {
1167 AUD_del_capture(vs->audio_cap, vs);
1168 vs->audio_cap = NULL;
1169 }
1170}
1171
198a0039
GH
1172static void vnc_disconnect_start(VncState *vs)
1173{
04d2529d 1174 if (vs->disconnecting) {
198a0039 1175 return;
04d2529d 1176 }
8cf36489 1177 vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
04d2529d
DB
1178 if (vs->ioc_tag) {
1179 g_source_remove(vs->ioc_tag);
1180 }
1181 qio_channel_close(vs->ioc, NULL);
1182 vs->disconnecting = TRUE;
198a0039
GH
1183}
1184
7536ee4b 1185void vnc_disconnect_finish(VncState *vs)
198a0039 1186{
7d964c9d
CC
1187 int i;
1188
bd023f95
CC
1189 vnc_jobs_join(vs); /* Wait encoding jobs */
1190
1191 vnc_lock_output(vs);
fb6ba0d5 1192 vnc_qmp_event(vs, QAPI_EVENT_VNC_DISCONNECTED);
0d72f3d3 1193
5d418e3b
CC
1194 buffer_free(&vs->input);
1195 buffer_free(&vs->output);
4a80dba3 1196
fb6ba0d5 1197 qapi_free_VncClientInfo(vs->info);
4a80dba3 1198
161c4f20 1199 vnc_zlib_clear(vs);
380282b0 1200 vnc_tight_clear(vs);
148954fa 1201 vnc_zrle_clear(vs);
161c4f20 1202
198a0039
GH
1203#ifdef CONFIG_VNC_SASL
1204 vnc_sasl_client_cleanup(vs);
1205#endif /* CONFIG_VNC_SASL */
1206 audio_del(vs);
7bc9318b 1207 vnc_release_modifiers(vs);
198a0039 1208
6fd8e79a
TH
1209 if (vs->initialized) {
1210 QTAILQ_REMOVE(&vs->vd->clients, vs, next);
1211 qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
c7628bff
GH
1212 if (QTAILQ_EMPTY(&vs->vd->clients)) {
1213 /* last client gone */
1214 vnc_update_server_surface(vs->vd);
1215 }
6fd8e79a 1216 }
41b4bef6 1217
3a0558b5
GH
1218 if (vs->vd->lock_key_sync)
1219 qemu_remove_led_event_handler(vs->led);
bd023f95
CC
1220 vnc_unlock_output(vs);
1221
bd023f95 1222 qemu_mutex_destroy(&vs->output_mutex);
6fd8e79a
TH
1223 if (vs->bh != NULL) {
1224 qemu_bh_delete(vs->bh);
1225 }
175b2a6e 1226 buffer_free(&vs->jobs_buffer);
175b2a6e 1227
7d964c9d 1228 for (i = 0; i < VNC_STAT_ROWS; ++i) {
7267c094 1229 g_free(vs->lossy_rect[i]);
7d964c9d 1230 }
7267c094 1231 g_free(vs->lossy_rect);
04d2529d
DB
1232
1233 object_unref(OBJECT(vs->ioc));
1234 vs->ioc = NULL;
1235 object_unref(OBJECT(vs->sioc));
1236 vs->sioc = NULL;
7267c094 1237 g_free(vs);
198a0039 1238}
2f9606b3 1239
04d2529d 1240ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp)
24236869 1241{
04d2529d
DB
1242 if (ret <= 0) {
1243 if (ret == 0) {
1244 VNC_DEBUG("Closing down client sock: EOF\n");
1245 } else if (ret != QIO_CHANNEL_ERR_BLOCK) {
1246 VNC_DEBUG("Closing down client sock: ret %d (%s)\n",
1247 ret, errp ? error_get_pretty(*errp) : "Unknown");
ea01e5fd 1248 }
24236869 1249
198a0039 1250 vnc_disconnect_start(vs);
04d2529d
DB
1251 if (errp) {
1252 error_free(*errp);
1253 *errp = NULL;
1254 }
28a76be8 1255 return 0;
24236869
FB
1256 }
1257 return ret;
1258}
1259
5fb6c7a8
AL
1260
1261void vnc_client_error(VncState *vs)
24236869 1262{
198a0039
GH
1263 VNC_DEBUG("Closing down client sock: protocol error\n");
1264 vnc_disconnect_start(vs);
24236869
FB
1265}
1266
3e305e4a 1267
2f9606b3
AL
1268/*
1269 * Called to write a chunk of data to the client socket. The data may
1270 * be the raw data, or may have already been encoded by SASL.
1271 * The data will be written either straight onto the socket, or
1272 * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1273 *
1274 * NB, it is theoretically possible to have 2 layers of encryption,
1275 * both SASL, and this TLS layer. It is highly unlikely in practice
1276 * though, since SASL encryption will typically be a no-op if TLS
1277 * is active
1278 *
1279 * Returns the number of bytes written, which may be less than
1280 * the requested 'datalen' if the socket would block. Returns
1281 * -1 on error, and disconnects the client socket.
1282 */
fdd1ab6a 1283ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
24236869 1284{
04d2529d 1285 Error *err = NULL;
fdd1ab6a 1286 ssize_t ret;
2cc45228
DB
1287 ret = qio_channel_write(
1288 vs->ioc, (const char *)data, datalen, &err);
23decc87 1289 VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
04d2529d 1290 return vnc_client_io_error(vs, ret, &err);
2f9606b3
AL
1291}
1292
1293
1294/*
1295 * Called to write buffered data to the client socket, when not
1296 * using any SASL SSF encryption layers. Will write as much data
1297 * as possible without blocking. If all buffered data is written,
1298 * will switch the FD poll() handler back to read monitoring.
1299 *
1300 * Returns the number of bytes written, which may be less than
1301 * the buffered output data if the socket would block. Returns
1302 * -1 on error, and disconnects the client socket.
1303 */
fdd1ab6a 1304static ssize_t vnc_client_write_plain(VncState *vs)
2f9606b3 1305{
fdd1ab6a 1306 ssize_t ret;
2f9606b3
AL
1307
1308#ifdef CONFIG_VNC_SASL
23decc87 1309 VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
2f9606b3
AL
1310 vs->output.buffer, vs->output.capacity, vs->output.offset,
1311 vs->sasl.waitWriteSSF);
1312
1313 if (vs->sasl.conn &&
1314 vs->sasl.runSSF &&
1315 vs->sasl.waitWriteSSF) {
1316 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
1317 if (ret)
1318 vs->sasl.waitWriteSSF -= ret;
1319 } else
1320#endif /* CONFIG_VNC_SASL */
1321 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
24236869 1322 if (!ret)
2f9606b3 1323 return 0;
24236869 1324
32ed2680 1325 buffer_advance(&vs->output, ret);
24236869
FB
1326
1327 if (vs->output.offset == 0) {
04d2529d
DB
1328 if (vs->ioc_tag) {
1329 g_source_remove(vs->ioc_tag);
1330 }
1331 vs->ioc_tag = qio_channel_add_watch(
1332 vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
24236869 1333 }
2f9606b3
AL
1334
1335 return ret;
1336}
1337
1338
1339/*
1340 * First function called whenever there is data to be written to
1341 * the client socket. Will delegate actual work according to whether
1342 * SASL SSF layers are enabled (thus requiring encryption calls)
1343 */
04d2529d 1344static void vnc_client_write_locked(VncState *vs)
2f9606b3 1345{
2f9606b3
AL
1346#ifdef CONFIG_VNC_SASL
1347 if (vs->sasl.conn &&
1348 vs->sasl.runSSF &&
9678d950
BS
1349 !vs->sasl.waitWriteSSF) {
1350 vnc_client_write_sasl(vs);
1351 } else
2f9606b3 1352#endif /* CONFIG_VNC_SASL */
7536ee4b 1353 {
d5f04223 1354 vnc_client_write_plain(vs);
7536ee4b 1355 }
24236869
FB
1356}
1357
04d2529d 1358static void vnc_client_write(VncState *vs)
bd023f95 1359{
bd023f95
CC
1360
1361 vnc_lock_output(vs);
d5f04223 1362 if (vs->output.offset) {
04d2529d
DB
1363 vnc_client_write_locked(vs);
1364 } else if (vs->ioc != NULL) {
1365 if (vs->ioc_tag) {
1366 g_source_remove(vs->ioc_tag);
1367 }
1368 vs->ioc_tag = qio_channel_add_watch(
1369 vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
bd023f95
CC
1370 }
1371 vnc_unlock_output(vs);
1372}
1373
5fb6c7a8 1374void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
24236869
FB
1375{
1376 vs->read_handler = func;
1377 vs->read_handler_expect = expecting;
1378}
1379
2f9606b3
AL
1380
1381/*
1382 * Called to read a chunk of data from the client socket. The data may
1383 * be the raw data, or may need to be further decoded by SASL.
1384 * The data will be read either straight from to the socket, or
1385 * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1386 *
1387 * NB, it is theoretically possible to have 2 layers of encryption,
1388 * both SASL, and this TLS layer. It is highly unlikely in practice
1389 * though, since SASL encryption will typically be a no-op if TLS
1390 * is active
1391 *
1392 * Returns the number of bytes read, which may be less than
1393 * the requested 'datalen' if the socket would block. Returns
1394 * -1 on error, and disconnects the client socket.
1395 */
fdd1ab6a 1396ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
24236869 1397{
fdd1ab6a 1398 ssize_t ret;
04d2529d 1399 Error *err = NULL;
2cc45228
DB
1400 ret = qio_channel_read(
1401 vs->ioc, (char *)data, datalen, &err);
23decc87 1402 VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
04d2529d 1403 return vnc_client_io_error(vs, ret, &err);
2f9606b3 1404}
24236869 1405
2f9606b3
AL
1406
1407/*
1408 * Called to read data from the client socket to the input buffer,
1409 * when not using any SASL SSF encryption layers. Will read as much
1410 * data as possible without blocking.
1411 *
1412 * Returns the number of bytes read. Returns -1 on error, and
1413 * disconnects the client socket.
1414 */
fdd1ab6a 1415static ssize_t vnc_client_read_plain(VncState *vs)
2f9606b3 1416{
fdd1ab6a 1417 ssize_t ret;
23decc87 1418 VNC_DEBUG("Read plain %p size %zd offset %zd\n",
2f9606b3
AL
1419 vs->input.buffer, vs->input.capacity, vs->input.offset);
1420 buffer_reserve(&vs->input, 4096);
1421 ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
1422 if (!ret)
1423 return 0;
24236869 1424 vs->input.offset += ret;
2f9606b3
AL
1425 return ret;
1426}
1427
175b2a6e
CC
1428static void vnc_jobs_bh(void *opaque)
1429{
1430 VncState *vs = opaque;
1431
1432 vnc_jobs_consume_buffer(vs);
1433}
2f9606b3
AL
1434
1435/*
1436 * First function called whenever there is more data to be read from
1437 * the client socket. Will delegate actual work according to whether
1438 * SASL SSF layers are enabled (thus requiring decryption calls)
1439 */
04d2529d 1440static void vnc_client_read(VncState *vs)
2f9606b3 1441{
fdd1ab6a 1442 ssize_t ret;
2f9606b3
AL
1443
1444#ifdef CONFIG_VNC_SASL
1445 if (vs->sasl.conn && vs->sasl.runSSF)
1446 ret = vnc_client_read_sasl(vs);
1447 else
1448#endif /* CONFIG_VNC_SASL */
d5f04223 1449 ret = vnc_client_read_plain(vs);
198a0039 1450 if (!ret) {
04d2529d 1451 if (vs->disconnecting) {
198a0039 1452 vnc_disconnect_finish(vs);
04d2529d 1453 }
28a76be8 1454 return;
198a0039 1455 }
24236869
FB
1456
1457 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
28a76be8
AL
1458 size_t len = vs->read_handler_expect;
1459 int ret;
1460
1461 ret = vs->read_handler(vs, vs->input.buffer, len);
04d2529d 1462 if (vs->disconnecting) {
198a0039 1463 vnc_disconnect_finish(vs);
28a76be8 1464 return;
198a0039 1465 }
28a76be8
AL
1466
1467 if (!ret) {
32ed2680 1468 buffer_advance(&vs->input, len);
28a76be8
AL
1469 } else {
1470 vs->read_handler_expect = ret;
1471 }
24236869
FB
1472 }
1473}
1474
04d2529d
DB
1475gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED,
1476 GIOCondition condition, void *opaque)
1477{
1478 VncState *vs = opaque;
1479 if (condition & G_IO_IN) {
1480 vnc_client_read(vs);
1481 }
1482 if (condition & G_IO_OUT) {
1483 vnc_client_write(vs);
1484 }
1485 return TRUE;
1486}
1487
1488
5fb6c7a8 1489void vnc_write(VncState *vs, const void *data, size_t len)
24236869
FB
1490{
1491 buffer_reserve(&vs->output, len);
1492
04d2529d
DB
1493 if (vs->ioc != NULL && buffer_empty(&vs->output)) {
1494 if (vs->ioc_tag) {
1495 g_source_remove(vs->ioc_tag);
1496 }
1497 vs->ioc_tag = qio_channel_add_watch(
1498 vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL);
24236869
FB
1499 }
1500
1501 buffer_append(&vs->output, data, len);
1502}
1503
5fb6c7a8 1504void vnc_write_s32(VncState *vs, int32_t value)
24236869
FB
1505{
1506 vnc_write_u32(vs, *(uint32_t *)&value);
1507}
1508
5fb6c7a8 1509void vnc_write_u32(VncState *vs, uint32_t value)
24236869
FB
1510{
1511 uint8_t buf[4];
1512
1513 buf[0] = (value >> 24) & 0xFF;
1514 buf[1] = (value >> 16) & 0xFF;
1515 buf[2] = (value >> 8) & 0xFF;
1516 buf[3] = value & 0xFF;
1517
1518 vnc_write(vs, buf, 4);
1519}
1520
5fb6c7a8 1521void vnc_write_u16(VncState *vs, uint16_t value)
24236869 1522{
64f5a135 1523 uint8_t buf[2];
24236869
FB
1524
1525 buf[0] = (value >> 8) & 0xFF;
1526 buf[1] = value & 0xFF;
1527
1528 vnc_write(vs, buf, 2);
1529}
1530
5fb6c7a8 1531void vnc_write_u8(VncState *vs, uint8_t value)
24236869
FB
1532{
1533 vnc_write(vs, (char *)&value, 1);
1534}
1535
5fb6c7a8 1536void vnc_flush(VncState *vs)
24236869 1537{
bd023f95 1538 vnc_lock_output(vs);
d5f04223 1539 if (vs->ioc != NULL && vs->output.offset) {
bd023f95
CC
1540 vnc_client_write_locked(vs);
1541 }
1542 vnc_unlock_output(vs);
24236869
FB
1543}
1544
71a8cdec 1545static uint8_t read_u8(uint8_t *data, size_t offset)
24236869
FB
1546{
1547 return data[offset];
1548}
1549
71a8cdec 1550static uint16_t read_u16(uint8_t *data, size_t offset)
24236869
FB
1551{
1552 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
1553}
1554
71a8cdec 1555static int32_t read_s32(uint8_t *data, size_t offset)
24236869
FB
1556{
1557 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
28a76be8 1558 (data[offset + 2] << 8) | data[offset + 3]);
24236869
FB
1559}
1560
5fb6c7a8 1561uint32_t read_u32(uint8_t *data, size_t offset)
24236869
FB
1562{
1563 return ((data[offset] << 24) | (data[offset + 1] << 16) |
28a76be8 1564 (data[offset + 2] << 8) | data[offset + 3]);
24236869
FB
1565}
1566
60fe76f3 1567static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
24236869
FB
1568{
1569}
1570
9e8dd451 1571static void check_pointer_type_change(Notifier *notifier, void *data)
564c337e 1572{
37c34d9d 1573 VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
14768eba 1574 int absolute = qemu_input_is_absolute();
37c34d9d 1575
29fa4ed9 1576 if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
bd023f95 1577 vnc_lock_output(vs);
46a183da 1578 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
28a76be8
AL
1579 vnc_write_u8(vs, 0);
1580 vnc_write_u16(vs, 1);
1581 vnc_framebuffer_update(vs, absolute, 0,
bea60dd7
PL
1582 pixman_image_get_width(vs->vd->server),
1583 pixman_image_get_height(vs->vd->server),
29fa4ed9 1584 VNC_ENCODING_POINTER_TYPE_CHANGE);
bd023f95 1585 vnc_unlock_output(vs);
28a76be8 1586 vnc_flush(vs);
564c337e
FB
1587 }
1588 vs->absolute = absolute;
1589}
1590
24236869
FB
1591static void pointer_event(VncState *vs, int button_mask, int x, int y)
1592{
7fb1cf16 1593 static uint32_t bmap[INPUT_BUTTON__MAX] = {
14768eba
GH
1594 [INPUT_BUTTON_LEFT] = 0x01,
1595 [INPUT_BUTTON_MIDDLE] = 0x02,
1596 [INPUT_BUTTON_RIGHT] = 0x04,
f22d0af0
GH
1597 [INPUT_BUTTON_WHEEL_UP] = 0x08,
1598 [INPUT_BUTTON_WHEEL_DOWN] = 0x10,
14768eba
GH
1599 };
1600 QemuConsole *con = vs->vd->dcl.con;
bea60dd7
PL
1601 int width = pixman_image_get_width(vs->vd->server);
1602 int height = pixman_image_get_height(vs->vd->server);
24236869 1603
14768eba
GH
1604 if (vs->last_bmask != button_mask) {
1605 qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
1606 vs->last_bmask = button_mask;
1607 }
564c337e
FB
1608
1609 if (vs->absolute) {
14768eba
GH
1610 qemu_input_queue_abs(con, INPUT_AXIS_X, x, width);
1611 qemu_input_queue_abs(con, INPUT_AXIS_Y, y, height);
29fa4ed9 1612 } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
14768eba
GH
1613 qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF);
1614 qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF);
564c337e 1615 } else {
14768eba
GH
1616 if (vs->last_x != -1) {
1617 qemu_input_queue_rel(con, INPUT_AXIS_X, x - vs->last_x);
1618 qemu_input_queue_rel(con, INPUT_AXIS_Y, y - vs->last_y);
1619 }
28a76be8
AL
1620 vs->last_x = x;
1621 vs->last_y = y;
24236869 1622 }
14768eba 1623 qemu_input_event_sync();
24236869
FB
1624}
1625
64f5a135
FB
1626static void reset_keys(VncState *vs)
1627{
1628 int i;
1629 for(i = 0; i < 256; i++) {
1630 if (vs->modifiers_state[i]) {
8d447d10 1631 qemu_input_event_send_key_number(vs->vd->dcl.con, i, false);
64f5a135
FB
1632 vs->modifiers_state[i] = 0;
1633 }
1634 }
1635}
1636
a528b80c
AZ
1637static void press_key(VncState *vs, int keysym)
1638{
44bb61c8 1639 int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
8d447d10 1640 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
2deb4acc 1641 qemu_input_event_send_key_delay(0);
8d447d10 1642 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
2deb4acc 1643 qemu_input_event_send_key_delay(0);
a528b80c
AZ
1644}
1645
ab99e5c1
LL
1646static int current_led_state(VncState *vs)
1647{
1648 int ledstate = 0;
1649
1650 if (vs->modifiers_state[0x46]) {
1651 ledstate |= QEMU_SCROLL_LOCK_LED;
1652 }
1653 if (vs->modifiers_state[0x45]) {
1654 ledstate |= QEMU_NUM_LOCK_LED;
1655 }
1656 if (vs->modifiers_state[0x3a]) {
1657 ledstate |= QEMU_CAPS_LOCK_LED;
1658 }
1659
1660 return ledstate;
1661}
1662
1663static void vnc_led_state_change(VncState *vs)
1664{
1665 int ledstate = 0;
1666
1667 if (!vnc_has_feature(vs, VNC_FEATURE_LED_STATE)) {
1668 return;
1669 }
1670
1671 ledstate = current_led_state(vs);
1672 vnc_lock_output(vs);
1673 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1674 vnc_write_u8(vs, 0);
1675 vnc_write_u16(vs, 1);
1676 vnc_framebuffer_update(vs, 0, 0, 1, 1, VNC_ENCODING_LED_STATE);
1677 vnc_write_u8(vs, ledstate);
1678 vnc_unlock_output(vs);
1679 vnc_flush(vs);
1680}
1681
7ffb82ca
GH
1682static void kbd_leds(void *opaque, int ledstate)
1683{
1684 VncState *vs = opaque;
96f3d174 1685 int caps, num, scr;
1483adcf 1686 bool has_changed = (ledstate != current_led_state(vs));
7ffb82ca 1687
40066175
GH
1688 trace_vnc_key_guest_leds((ledstate & QEMU_CAPS_LOCK_LED),
1689 (ledstate & QEMU_NUM_LOCK_LED),
1690 (ledstate & QEMU_SCROLL_LOCK_LED));
1691
7ffb82ca
GH
1692 caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
1693 num = ledstate & QEMU_NUM_LOCK_LED ? 1 : 0;
96f3d174 1694 scr = ledstate & QEMU_SCROLL_LOCK_LED ? 1 : 0;
7ffb82ca
GH
1695
1696 if (vs->modifiers_state[0x3a] != caps) {
1697 vs->modifiers_state[0x3a] = caps;
1698 }
1699 if (vs->modifiers_state[0x45] != num) {
1700 vs->modifiers_state[0x45] = num;
1701 }
96f3d174
LL
1702 if (vs->modifiers_state[0x46] != scr) {
1703 vs->modifiers_state[0x46] = scr;
1704 }
ab99e5c1
LL
1705
1706 /* Sending the current led state message to the client */
1483adcf 1707 if (has_changed) {
ab99e5c1
LL
1708 vnc_led_state_change(vs);
1709 }
7ffb82ca
GH
1710}
1711
9ca313aa 1712static void do_key_event(VncState *vs, int down, int keycode, int sym)
24236869 1713{
64f5a135
FB
1714 /* QEMU console switch */
1715 switch(keycode) {
1716 case 0x2a: /* Left Shift */
1717 case 0x36: /* Right Shift */
1718 case 0x1d: /* Left CTRL */
1719 case 0x9d: /* Right CTRL */
1720 case 0x38: /* Left ALT */
1721 case 0xb8: /* Right ALT */
1722 if (down)
1723 vs->modifiers_state[keycode] = 1;
1724 else
1725 vs->modifiers_state[keycode] = 0;
1726 break;
5fafdf24 1727 case 0x02 ... 0x0a: /* '1' to '9' keys */
1d0d59fe
GH
1728 if (vs->vd->dcl.con == NULL &&
1729 down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
64f5a135
FB
1730 /* Reset the modifiers sent to the current console */
1731 reset_keys(vs);
1732 console_select(keycode - 0x02);
1733 return;
1734 }
1735 break;
28a76be8
AL
1736 case 0x3a: /* CapsLock */
1737 case 0x45: /* NumLock */
7ffb82ca 1738 if (down)
a528b80c
AZ
1739 vs->modifiers_state[keycode] ^= 1;
1740 break;
1741 }
1742
e7b2aacc
LL
1743 /* Turn off the lock state sync logic if the client support the led
1744 state extension.
1745 */
9892088b 1746 if (down && vs->vd->lock_key_sync &&
e7b2aacc 1747 !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
3a0558b5 1748 keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
a528b80c
AZ
1749 /* If the numlock state needs to change then simulate an additional
1750 keypress before sending this one. This will happen if the user
1751 toggles numlock away from the VNC window.
1752 */
753b4053 1753 if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
a528b80c 1754 if (!vs->modifiers_state[0x45]) {
40066175 1755 trace_vnc_key_sync_numlock(true);
a528b80c
AZ
1756 vs->modifiers_state[0x45] = 1;
1757 press_key(vs, 0xff7f);
1758 }
1759 } else {
1760 if (vs->modifiers_state[0x45]) {
40066175 1761 trace_vnc_key_sync_numlock(false);
a528b80c
AZ
1762 vs->modifiers_state[0x45] = 0;
1763 press_key(vs, 0xff7f);
1764 }
1765 }
64f5a135 1766 }
24236869 1767
9892088b 1768 if (down && vs->vd->lock_key_sync &&
e7b2aacc 1769 !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
3a0558b5 1770 ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
6b132502
GH
1771 /* If the capslock state needs to change then simulate an additional
1772 keypress before sending this one. This will happen if the user
1773 toggles capslock away from the VNC window.
1774 */
1775 int uppercase = !!(sym >= 'A' && sym <= 'Z');
1776 int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
1777 int capslock = !!(vs->modifiers_state[0x3a]);
1778 if (capslock) {
1779 if (uppercase == shift) {
40066175 1780 trace_vnc_key_sync_capslock(false);
6b132502
GH
1781 vs->modifiers_state[0x3a] = 0;
1782 press_key(vs, 0xffe5);
1783 }
1784 } else {
1785 if (uppercase != shift) {
40066175 1786 trace_vnc_key_sync_capslock(true);
6b132502
GH
1787 vs->modifiers_state[0x3a] = 1;
1788 press_key(vs, 0xffe5);
1789 }
1790 }
1791 }
1792
81c0d5a6 1793 if (qemu_console_is_graphic(NULL)) {
8d447d10 1794 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
64f5a135 1795 } else {
e26437c2
GH
1796 bool numlock = vs->modifiers_state[0x45];
1797 bool control = (vs->modifiers_state[0x1d] ||
1798 vs->modifiers_state[0x9d]);
64f5a135
FB
1799 /* QEMU console emulation */
1800 if (down) {
1801 switch (keycode) {
1802 case 0x2a: /* Left Shift */
1803 case 0x36: /* Right Shift */
1804 case 0x1d: /* Left CTRL */
1805 case 0x9d: /* Right CTRL */
1806 case 0x38: /* Left ALT */
1807 case 0xb8: /* Right ALT */
1808 break;
1809 case 0xc8:
1810 kbd_put_keysym(QEMU_KEY_UP);
1811 break;
1812 case 0xd0:
1813 kbd_put_keysym(QEMU_KEY_DOWN);
1814 break;
1815 case 0xcb:
1816 kbd_put_keysym(QEMU_KEY_LEFT);
1817 break;
1818 case 0xcd:
1819 kbd_put_keysym(QEMU_KEY_RIGHT);
1820 break;
1821 case 0xd3:
1822 kbd_put_keysym(QEMU_KEY_DELETE);
1823 break;
1824 case 0xc7:
1825 kbd_put_keysym(QEMU_KEY_HOME);
1826 break;
1827 case 0xcf:
1828 kbd_put_keysym(QEMU_KEY_END);
1829 break;
1830 case 0xc9:
1831 kbd_put_keysym(QEMU_KEY_PAGEUP);
1832 break;
1833 case 0xd1:
1834 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1835 break;
bb0a18e1
GH
1836
1837 case 0x47:
1838 kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
1839 break;
1840 case 0x48:
1841 kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
1842 break;
1843 case 0x49:
1844 kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
1845 break;
1846 case 0x4b:
1847 kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
1848 break;
1849 case 0x4c:
1850 kbd_put_keysym('5');
1851 break;
1852 case 0x4d:
1853 kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
1854 break;
1855 case 0x4f:
1856 kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
1857 break;
1858 case 0x50:
1859 kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
1860 break;
1861 case 0x51:
1862 kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
1863 break;
1864 case 0x52:
1865 kbd_put_keysym('0');
1866 break;
1867 case 0x53:
1868 kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
1869 break;
1870
1871 case 0xb5:
1872 kbd_put_keysym('/');
1873 break;
1874 case 0x37:
1875 kbd_put_keysym('*');
1876 break;
1877 case 0x4a:
1878 kbd_put_keysym('-');
1879 break;
1880 case 0x4e:
1881 kbd_put_keysym('+');
1882 break;
1883 case 0x9c:
1884 kbd_put_keysym('\n');
1885 break;
1886
64f5a135 1887 default:
e26437c2
GH
1888 if (control) {
1889 kbd_put_keysym(sym & 0x1f);
1890 } else {
1891 kbd_put_keysym(sym);
1892 }
64f5a135
FB
1893 break;
1894 }
1895 }
1896 }
24236869
FB
1897}
1898
7bc9318b
GH
1899static void vnc_release_modifiers(VncState *vs)
1900{
1901 static const int keycodes[] = {
1902 /* shift, control, alt keys, both left & right */
1903 0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8,
1904 };
1905 int i, keycode;
1906
81c0d5a6 1907 if (!qemu_console_is_graphic(NULL)) {
7bc9318b
GH
1908 return;
1909 }
1910 for (i = 0; i < ARRAY_SIZE(keycodes); i++) {
1911 keycode = keycodes[i];
1912 if (!vs->modifiers_state[keycode]) {
1913 continue;
1914 }
8d447d10 1915 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
7bc9318b
GH
1916 }
1917}
1918
40066175
GH
1919static const char *code2name(int keycode)
1920{
1921 return QKeyCode_lookup[qemu_input_key_number_to_qcode(keycode)];
1922}
1923
bdbd7676
FB
1924static void key_event(VncState *vs, int down, uint32_t sym)
1925{
9ca313aa 1926 int keycode;
4a93fe17 1927 int lsym = sym;
9ca313aa 1928
81c0d5a6 1929 if (lsym >= 'A' && lsym <= 'Z' && qemu_console_is_graphic(NULL)) {
4a93fe17
GH
1930 lsym = lsym - 'A' + 'a';
1931 }
9ca313aa 1932
44bb61c8 1933 keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
40066175 1934 trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
9ca313aa
AL
1935 do_key_event(vs, down, keycode, sym);
1936}
1937
1938static void ext_key_event(VncState *vs, int down,
1939 uint32_t sym, uint16_t keycode)
1940{
1941 /* if the user specifies a keyboard layout, always use it */
40066175 1942 if (keyboard_layout) {
9ca313aa 1943 key_event(vs, down, sym);
40066175
GH
1944 } else {
1945 trace_vnc_key_event_ext(down, sym, keycode, code2name(keycode));
9ca313aa 1946 do_key_event(vs, down, keycode, sym);
40066175 1947 }
bdbd7676
FB
1948}
1949
24236869 1950static void framebuffer_update_request(VncState *vs, int incremental,
bea60dd7 1951 int x, int y, int w, int h)
24236869 1952{
24236869 1953 vs->need_update = 1;
bea60dd7
PL
1954
1955 if (incremental) {
1956 return;
24236869 1957 }
bea60dd7 1958
07535a89 1959 vs->force_update = 1;
f7b3d68c 1960 vnc_set_area_dirty(vs->dirty, vs->vd, x, y, w, h);
24236869
FB
1961}
1962
9ca313aa
AL
1963static void send_ext_key_event_ack(VncState *vs)
1964{
bd023f95 1965 vnc_lock_output(vs);
46a183da 1966 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
9ca313aa
AL
1967 vnc_write_u8(vs, 0);
1968 vnc_write_u16(vs, 1);
d39fa6d8 1969 vnc_framebuffer_update(vs, 0, 0,
bea60dd7
PL
1970 pixman_image_get_width(vs->vd->server),
1971 pixman_image_get_height(vs->vd->server),
29fa4ed9 1972 VNC_ENCODING_EXT_KEY_EVENT);
bd023f95 1973 vnc_unlock_output(vs);
9ca313aa
AL
1974 vnc_flush(vs);
1975}
1976
429a8ed3 1977static void send_ext_audio_ack(VncState *vs)
1978{
bd023f95 1979 vnc_lock_output(vs);
46a183da 1980 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
429a8ed3 1981 vnc_write_u8(vs, 0);
1982 vnc_write_u16(vs, 1);
d39fa6d8 1983 vnc_framebuffer_update(vs, 0, 0,
bea60dd7
PL
1984 pixman_image_get_width(vs->vd->server),
1985 pixman_image_get_height(vs->vd->server),
29fa4ed9 1986 VNC_ENCODING_AUDIO);
bd023f95 1987 vnc_unlock_output(vs);
429a8ed3 1988 vnc_flush(vs);
1989}
1990
24236869
FB
1991static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1992{
1993 int i;
29fa4ed9 1994 unsigned int enc = 0;
24236869 1995
29fa4ed9 1996 vs->features = 0;
a9f20d31 1997 vs->vnc_encoding = 0;
d1af0e05
CC
1998 vs->tight.compression = 9;
1999 vs->tight.quality = -1; /* Lossless by default */
564c337e 2000 vs->absolute = -1;
24236869 2001
8a0f0d0c
CC
2002 /*
2003 * Start from the end because the encodings are sent in order of preference.
e5bed759 2004 * This way the preferred encoding (first encoding defined in the array)
8a0f0d0c
CC
2005 * will be set at the end of the loop.
2006 */
24236869 2007 for (i = n_encodings - 1; i >= 0; i--) {
29fa4ed9
AL
2008 enc = encodings[i];
2009 switch (enc) {
2010 case VNC_ENCODING_RAW:
a9f20d31 2011 vs->vnc_encoding = enc;
29fa4ed9
AL
2012 break;
2013 case VNC_ENCODING_COPYRECT:
753b4053 2014 vs->features |= VNC_FEATURE_COPYRECT_MASK;
29fa4ed9
AL
2015 break;
2016 case VNC_ENCODING_HEXTILE:
2017 vs->features |= VNC_FEATURE_HEXTILE_MASK;
a9f20d31 2018 vs->vnc_encoding = enc;
29fa4ed9 2019 break;
380282b0
CC
2020 case VNC_ENCODING_TIGHT:
2021 vs->features |= VNC_FEATURE_TIGHT_MASK;
2022 vs->vnc_encoding = enc;
2023 break;
fe3e7f2d 2024#ifdef CONFIG_VNC_PNG
efe556ad
CC
2025 case VNC_ENCODING_TIGHT_PNG:
2026 vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
2027 vs->vnc_encoding = enc;
2028 break;
fe3e7f2d 2029#endif
059cef40
AL
2030 case VNC_ENCODING_ZLIB:
2031 vs->features |= VNC_FEATURE_ZLIB_MASK;
a9f20d31 2032 vs->vnc_encoding = enc;
059cef40 2033 break;
148954fa
CC
2034 case VNC_ENCODING_ZRLE:
2035 vs->features |= VNC_FEATURE_ZRLE_MASK;
2036 vs->vnc_encoding = enc;
2037 break;
2038 case VNC_ENCODING_ZYWRLE:
2039 vs->features |= VNC_FEATURE_ZYWRLE_MASK;
2040 vs->vnc_encoding = enc;
2041 break;
29fa4ed9
AL
2042 case VNC_ENCODING_DESKTOPRESIZE:
2043 vs->features |= VNC_FEATURE_RESIZE_MASK;
2044 break;
2045 case VNC_ENCODING_POINTER_TYPE_CHANGE:
2046 vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
2047 break;
d467b679
GH
2048 case VNC_ENCODING_RICH_CURSOR:
2049 vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
91ec41dc
FZ
2050 if (vs->vd->cursor) {
2051 vnc_cursor_define(vs);
2052 }
d467b679 2053 break;
29fa4ed9 2054 case VNC_ENCODING_EXT_KEY_EVENT:
9ca313aa
AL
2055 send_ext_key_event_ack(vs);
2056 break;
29fa4ed9 2057 case VNC_ENCODING_AUDIO:
429a8ed3 2058 send_ext_audio_ack(vs);
2059 break;
29fa4ed9
AL
2060 case VNC_ENCODING_WMVi:
2061 vs->features |= VNC_FEATURE_WMVI_MASK;
ca4cca4d 2062 break;
ab99e5c1
LL
2063 case VNC_ENCODING_LED_STATE:
2064 vs->features |= VNC_FEATURE_LED_STATE_MASK;
2065 break;
fb437313 2066 case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
d1af0e05 2067 vs->tight.compression = (enc & 0x0F);
fb437313
AL
2068 break;
2069 case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
b31f519e
CC
2070 if (vs->vd->lossy) {
2071 vs->tight.quality = (enc & 0x0F);
2072 }
fb437313 2073 break;
29fa4ed9
AL
2074 default:
2075 VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
2076 break;
2077 }
24236869 2078 }
6356e472 2079 vnc_desktop_resize(vs);
9e8dd451 2080 check_pointer_type_change(&vs->mouse_mode_notifier, NULL);
ab99e5c1 2081 vnc_led_state_change(vs);
24236869
FB
2082}
2083
6cec5487
AL
2084static void set_pixel_conversion(VncState *vs)
2085{
9f64916d
GH
2086 pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf);
2087
2088 if (fmt == VNC_SERVER_FB_FORMAT) {
6cec5487 2089 vs->write_pixels = vnc_write_pixels_copy;
70a4568f 2090 vnc_hextile_set_pixel_conversion(vs, 0);
6cec5487
AL
2091 } else {
2092 vs->write_pixels = vnc_write_pixels_generic;
70a4568f 2093 vnc_hextile_set_pixel_conversion(vs, 1);
6cec5487
AL
2094 }
2095}
2096
24236869 2097static void set_pixel_format(VncState *vs,
28a76be8
AL
2098 int bits_per_pixel, int depth,
2099 int big_endian_flag, int true_color_flag,
2100 int red_max, int green_max, int blue_max,
2101 int red_shift, int green_shift, int blue_shift)
24236869 2102{
3512779a 2103 if (!true_color_flag) {
28a76be8 2104 vnc_client_error(vs);
3512779a
FB
2105 return;
2106 }
24236869 2107
e6908bfe
PM
2108 switch (bits_per_pixel) {
2109 case 8:
2110 case 16:
2111 case 32:
2112 break;
2113 default:
2114 vnc_client_error(vs);
2115 return;
2116 }
2117
4c65fed8 2118 vs->client_pf.rmax = red_max ? red_max : 0xFF;
9f64916d
GH
2119 vs->client_pf.rbits = hweight_long(red_max);
2120 vs->client_pf.rshift = red_shift;
2121 vs->client_pf.rmask = red_max << red_shift;
4c65fed8 2122 vs->client_pf.gmax = green_max ? green_max : 0xFF;
9f64916d
GH
2123 vs->client_pf.gbits = hweight_long(green_max);
2124 vs->client_pf.gshift = green_shift;
2125 vs->client_pf.gmask = green_max << green_shift;
4c65fed8 2126 vs->client_pf.bmax = blue_max ? blue_max : 0xFF;
9f64916d
GH
2127 vs->client_pf.bbits = hweight_long(blue_max);
2128 vs->client_pf.bshift = blue_shift;
2129 vs->client_pf.bmask = blue_max << blue_shift;
2130 vs->client_pf.bits_per_pixel = bits_per_pixel;
2131 vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
2132 vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
2133 vs->client_be = big_endian_flag;
6cec5487
AL
2134
2135 set_pixel_conversion(vs);
24236869 2136
1d0d59fe
GH
2137 graphic_hw_invalidate(vs->vd->dcl.con);
2138 graphic_hw_update(vs->vd->dcl.con);
24236869
FB
2139}
2140
ca4cca4d
AL
2141static void pixel_format_message (VncState *vs) {
2142 char pad[3] = { 0, 0, 0 };
2143
9f64916d
GH
2144 vs->client_pf = qemu_default_pixelformat(32);
2145
2146 vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */
2147 vnc_write_u8(vs, vs->client_pf.depth); /* depth */
ca4cca4d 2148
e2542fe2 2149#ifdef HOST_WORDS_BIGENDIAN
ca4cca4d
AL
2150 vnc_write_u8(vs, 1); /* big-endian-flag */
2151#else
2152 vnc_write_u8(vs, 0); /* big-endian-flag */
2153#endif
2154 vnc_write_u8(vs, 1); /* true-color-flag */
9f64916d
GH
2155 vnc_write_u16(vs, vs->client_pf.rmax); /* red-max */
2156 vnc_write_u16(vs, vs->client_pf.gmax); /* green-max */
2157 vnc_write_u16(vs, vs->client_pf.bmax); /* blue-max */
2158 vnc_write_u8(vs, vs->client_pf.rshift); /* red-shift */
2159 vnc_write_u8(vs, vs->client_pf.gshift); /* green-shift */
2160 vnc_write_u8(vs, vs->client_pf.bshift); /* blue-shift */
2161 vnc_write(vs, pad, 3); /* padding */
70a4568f
CC
2162
2163 vnc_hextile_set_pixel_conversion(vs, 0);
ca4cca4d 2164 vs->write_pixels = vnc_write_pixels_copy;
ca4cca4d
AL
2165}
2166
753b4053 2167static void vnc_colordepth(VncState *vs)
7eac3a87 2168{
753b4053 2169 if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
ca4cca4d 2170 /* Sending a WMVi message to notify the client*/
bd023f95 2171 vnc_lock_output(vs);
46a183da 2172 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
ca4cca4d
AL
2173 vnc_write_u8(vs, 0);
2174 vnc_write_u16(vs, 1); /* number of rects */
d39fa6d8 2175 vnc_framebuffer_update(vs, 0, 0,
bea60dd7
PL
2176 pixman_image_get_width(vs->vd->server),
2177 pixman_image_get_height(vs->vd->server),
d39fa6d8 2178 VNC_ENCODING_WMVi);
ca4cca4d 2179 pixel_format_message(vs);
bd023f95 2180 vnc_unlock_output(vs);
ca4cca4d 2181 vnc_flush(vs);
7eac3a87 2182 } else {
6cec5487 2183 set_pixel_conversion(vs);
7eac3a87
AL
2184 }
2185}
2186
60fe76f3 2187static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
24236869
FB
2188{
2189 int i;
2190 uint16_t limit;
2430ffe4
SS
2191 VncDisplay *vd = vs->vd;
2192
2193 if (data[0] > 3) {
0f7b2864 2194 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
2430ffe4 2195 }
24236869
FB
2196
2197 switch (data[0]) {
46a183da 2198 case VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
28a76be8
AL
2199 if (len == 1)
2200 return 20;
2201
2202 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
2203 read_u8(data, 6), read_u8(data, 7),
2204 read_u16(data, 8), read_u16(data, 10),
2205 read_u16(data, 12), read_u8(data, 14),
2206 read_u8(data, 15), read_u8(data, 16));
2207 break;
46a183da 2208 case VNC_MSG_CLIENT_SET_ENCODINGS:
28a76be8
AL
2209 if (len == 1)
2210 return 4;
24236869 2211
28a76be8 2212 if (len == 4) {
69dd5c9f
AL
2213 limit = read_u16(data, 2);
2214 if (limit > 0)
2215 return 4 + (limit * 4);
2216 } else
2217 limit = read_u16(data, 2);
24236869 2218
28a76be8
AL
2219 for (i = 0; i < limit; i++) {
2220 int32_t val = read_s32(data, 4 + (i * 4));
2221 memcpy(data + 4 + (i * 4), &val, sizeof(val));
2222 }
24236869 2223
28a76be8
AL
2224 set_encodings(vs, (int32_t *)(data + 4), limit);
2225 break;
46a183da 2226 case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
28a76be8
AL
2227 if (len == 1)
2228 return 10;
24236869 2229
28a76be8
AL
2230 framebuffer_update_request(vs,
2231 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
2232 read_u16(data, 6), read_u16(data, 8));
2233 break;
46a183da 2234 case VNC_MSG_CLIENT_KEY_EVENT:
28a76be8
AL
2235 if (len == 1)
2236 return 8;
24236869 2237
28a76be8
AL
2238 key_event(vs, read_u8(data, 1), read_u32(data, 4));
2239 break;
46a183da 2240 case VNC_MSG_CLIENT_POINTER_EVENT:
28a76be8
AL
2241 if (len == 1)
2242 return 6;
24236869 2243
28a76be8
AL
2244 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
2245 break;
46a183da 2246 case VNC_MSG_CLIENT_CUT_TEXT:
f9a70e79 2247 if (len == 1) {
28a76be8 2248 return 8;
f9a70e79 2249 }
28a76be8 2250 if (len == 8) {
baa7666c 2251 uint32_t dlen = read_u32(data, 4);
f9a70e79
PL
2252 if (dlen > (1 << 20)) {
2253 error_report("vnc: client_cut_text msg payload has %u bytes"
2254 " which exceeds our limit of 1MB.", dlen);
2255 vnc_client_error(vs);
2256 break;
2257 }
2258 if (dlen > 0) {
baa7666c 2259 return 8 + dlen;
f9a70e79 2260 }
baa7666c 2261 }
24236869 2262
28a76be8
AL
2263 client_cut_text(vs, read_u32(data, 4), data + 8);
2264 break;
46a183da 2265 case VNC_MSG_CLIENT_QEMU:
9ca313aa
AL
2266 if (len == 1)
2267 return 2;
2268
2269 switch (read_u8(data, 1)) {
46a183da 2270 case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
9ca313aa
AL
2271 if (len == 2)
2272 return 12;
2273
2274 ext_key_event(vs, read_u16(data, 2),
2275 read_u32(data, 4), read_u32(data, 8));
2276 break;
46a183da 2277 case VNC_MSG_CLIENT_QEMU_AUDIO:
429a8ed3 2278 if (len == 2)
2279 return 4;
2280
2281 switch (read_u16 (data, 2)) {
46a183da 2282 case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
429a8ed3 2283 audio_add(vs);
2284 break;
46a183da 2285 case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
429a8ed3 2286 audio_del(vs);
2287 break;
46a183da 2288 case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
429a8ed3 2289 if (len == 4)
2290 return 10;
2291 switch (read_u8(data, 4)) {
2292 case 0: vs->as.fmt = AUD_FMT_U8; break;
2293 case 1: vs->as.fmt = AUD_FMT_S8; break;
2294 case 2: vs->as.fmt = AUD_FMT_U16; break;
2295 case 3: vs->as.fmt = AUD_FMT_S16; break;
2296 case 4: vs->as.fmt = AUD_FMT_U32; break;
2297 case 5: vs->as.fmt = AUD_FMT_S32; break;
2298 default:
153130cd 2299 VNC_DEBUG("Invalid audio format %d\n", read_u8(data, 4));
429a8ed3 2300 vnc_client_error(vs);
2301 break;
2302 }
2303 vs->as.nchannels = read_u8(data, 5);
2304 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
153130cd
DB
2305 VNC_DEBUG("Invalid audio channel coount %d\n",
2306 read_u8(data, 5));
429a8ed3 2307 vnc_client_error(vs);
2308 break;
2309 }
2310 vs->as.freq = read_u32(data, 6);
2311 break;
2312 default:
153130cd 2313 VNC_DEBUG("Invalid audio message %d\n", read_u8(data, 4));
429a8ed3 2314 vnc_client_error(vs);
2315 break;
2316 }
2317 break;
2318
9ca313aa 2319 default:
153130cd 2320 VNC_DEBUG("Msg: %d\n", read_u16(data, 0));
9ca313aa
AL
2321 vnc_client_error(vs);
2322 break;
2323 }
2324 break;
24236869 2325 default:
153130cd 2326 VNC_DEBUG("Msg: %d\n", data[0]);
28a76be8
AL
2327 vnc_client_error(vs);
2328 break;
24236869 2329 }
5fafdf24 2330
24236869
FB
2331 vnc_read_when(vs, protocol_client_msg, 1);
2332 return 0;
2333}
2334
60fe76f3 2335static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
24236869 2336{
c35734b2 2337 char buf[1024];
8cf36489 2338 VncShareMode mode;
c35734b2 2339 int size;
24236869 2340
8cf36489
GH
2341 mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE;
2342 switch (vs->vd->share_policy) {
2343 case VNC_SHARE_POLICY_IGNORE:
2344 /*
2345 * Ignore the shared flag. Nothing to do here.
2346 *
2347 * Doesn't conform to the rfb spec but is traditional qemu
2348 * behavior, thus left here as option for compatibility
2349 * reasons.
2350 */
2351 break;
2352 case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE:
2353 /*
2354 * Policy: Allow clients ask for exclusive access.
2355 *
2356 * Implementation: When a client asks for exclusive access,
2357 * disconnect all others. Shared connects are allowed as long
2358 * as no exclusive connection exists.
2359 *
2360 * This is how the rfb spec suggests to handle the shared flag.
2361 */
2362 if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
2363 VncState *client;
2364 QTAILQ_FOREACH(client, &vs->vd->clients, next) {
2365 if (vs == client) {
2366 continue;
2367 }
2368 if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE &&
2369 client->share_mode != VNC_SHARE_MODE_SHARED) {
2370 continue;
2371 }
2372 vnc_disconnect_start(client);
2373 }
2374 }
2375 if (mode == VNC_SHARE_MODE_SHARED) {
2376 if (vs->vd->num_exclusive > 0) {
2377 vnc_disconnect_start(vs);
2378 return 0;
2379 }
2380 }
2381 break;
2382 case VNC_SHARE_POLICY_FORCE_SHARED:
2383 /*
2384 * Policy: Shared connects only.
2385 * Implementation: Disallow clients asking for exclusive access.
2386 *
2387 * Useful for shared desktop sessions where you don't want
2388 * someone forgetting to say -shared when running the vnc
2389 * client disconnect everybody else.
2390 */
2391 if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
2392 vnc_disconnect_start(vs);
2393 return 0;
2394 }
2395 break;
2396 }
2397 vnc_set_share_mode(vs, mode);
2398
e5f34cdd
GH
2399 if (vs->vd->num_shared > vs->vd->connections_limit) {
2400 vnc_disconnect_start(vs);
2401 return 0;
2402 }
2403
bea60dd7
PL
2404 vs->client_width = pixman_image_get_width(vs->vd->server);
2405 vs->client_height = pixman_image_get_height(vs->vd->server);
5862d195
GH
2406 vnc_write_u16(vs, vs->client_width);
2407 vnc_write_u16(vs, vs->client_height);
24236869 2408
ca4cca4d 2409 pixel_format_message(vs);
24236869 2410
c35734b2
TS
2411 if (qemu_name)
2412 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
2413 else
2414 size = snprintf(buf, sizeof(buf), "QEMU");
2415
2416 vnc_write_u32(vs, size);
2417 vnc_write(vs, buf, size);
24236869
FB
2418 vnc_flush(vs);
2419
4a80dba3 2420 vnc_client_cache_auth(vs);
fb6ba0d5 2421 vnc_qmp_event(vs, QAPI_EVENT_VNC_INITIALIZED);
4a80dba3 2422
24236869
FB
2423 vnc_read_when(vs, protocol_client_msg, 1);
2424
2425 return 0;
2426}
2427
5fb6c7a8
AL
2428void start_client_init(VncState *vs)
2429{
2430 vnc_read_when(vs, protocol_client_init, 1);
2431}
2432
70848515
TS
2433static void make_challenge(VncState *vs)
2434{
2435 int i;
2436
2437 srand(time(NULL)+getpid()+getpid()*987654+rand());
2438
2439 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
2440 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
2441}
2442
60fe76f3 2443static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
70848515 2444{
60fe76f3 2445 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
800567a6 2446 size_t i, pwlen;
60fe76f3 2447 unsigned char key[8];
3c9405a0 2448 time_t now = time(NULL);
60928458 2449 QCryptoCipher *cipher = NULL;
800567a6 2450 Error *err = NULL;
70848515 2451
1cd20f8b 2452 if (!vs->vd->password) {
28a76be8 2453 VNC_DEBUG("No password configured on server");
6bffdf0f 2454 goto reject;
70848515 2455 }
3c9405a0
GH
2456 if (vs->vd->expires < now) {
2457 VNC_DEBUG("Password is expired");
2458 goto reject;
2459 }
70848515
TS
2460
2461 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
2462
2463 /* Calculate the expected challenge response */
753b4053 2464 pwlen = strlen(vs->vd->password);
70848515 2465 for (i=0; i<sizeof(key); i++)
753b4053 2466 key[i] = i<pwlen ? vs->vd->password[i] : 0;
800567a6
DB
2467
2468 cipher = qcrypto_cipher_new(
2469 QCRYPTO_CIPHER_ALG_DES_RFB,
2470 QCRYPTO_CIPHER_MODE_ECB,
2471 key, G_N_ELEMENTS(key),
2472 &err);
2473 if (!cipher) {
2474 VNC_DEBUG("Cannot initialize cipher %s",
2475 error_get_pretty(err));
2476 error_free(err);
2477 goto reject;
2478 }
2479
a1695137 2480 if (qcrypto_cipher_encrypt(cipher,
800567a6
DB
2481 vs->challenge,
2482 response,
2483 VNC_AUTH_CHALLENGE_SIZE,
2484 &err) < 0) {
2485 VNC_DEBUG("Cannot encrypt challenge %s",
2486 error_get_pretty(err));
2487 error_free(err);
2488 goto reject;
2489 }
70848515
TS
2490
2491 /* Compare expected vs actual challenge response */
2492 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
e5bed759 2493 VNC_DEBUG("Client challenge response did not match\n");
6bffdf0f 2494 goto reject;
70848515 2495 } else {
28a76be8
AL
2496 VNC_DEBUG("Accepting VNC challenge response\n");
2497 vnc_write_u32(vs, 0); /* Accept auth */
2498 vnc_flush(vs);
70848515 2499
5fb6c7a8 2500 start_client_init(vs);
70848515 2501 }
60928458
GA
2502
2503 qcrypto_cipher_free(cipher);
70848515 2504 return 0;
6bffdf0f
GH
2505
2506reject:
2507 vnc_write_u32(vs, 1); /* Reject auth */
2508 if (vs->minor >= 8) {
2509 static const char err[] = "Authentication failed";
2510 vnc_write_u32(vs, sizeof(err));
2511 vnc_write(vs, err, sizeof(err));
2512 }
2513 vnc_flush(vs);
2514 vnc_client_error(vs);
60928458 2515 qcrypto_cipher_free(cipher);
6bffdf0f 2516 return 0;
70848515
TS
2517}
2518
5fb6c7a8 2519void start_auth_vnc(VncState *vs)
70848515
TS
2520{
2521 make_challenge(vs);
2522 /* Send client a 'random' challenge */
2523 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
2524 vnc_flush(vs);
2525
2526 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
469b15c6
TS
2527}
2528
2529
60fe76f3 2530static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
70848515
TS
2531{
2532 /* We only advertise 1 auth scheme at a time, so client
2533 * must pick the one we sent. Verify this */
7e7e2ebc 2534 if (data[0] != vs->auth) { /* Reject auth */
1263b7d6 2535 VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
70848515
TS
2536 vnc_write_u32(vs, 1);
2537 if (vs->minor >= 8) {
2538 static const char err[] = "Authentication failed";
2539 vnc_write_u32(vs, sizeof(err));
2540 vnc_write(vs, err, sizeof(err));
2541 }
2542 vnc_client_error(vs);
2543 } else { /* Accept requested auth */
2544 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
7e7e2ebc 2545 switch (vs->auth) {
70848515
TS
2546 case VNC_AUTH_NONE:
2547 VNC_DEBUG("Accept auth none\n");
a26c97ad
AZ
2548 if (vs->minor >= 8) {
2549 vnc_write_u32(vs, 0); /* Accept auth completion */
2550 vnc_flush(vs);
2551 }
5fb6c7a8 2552 start_client_init(vs);
70848515
TS
2553 break;
2554
2555 case VNC_AUTH_VNC:
2556 VNC_DEBUG("Start VNC auth\n");
5fb6c7a8
AL
2557 start_auth_vnc(vs);
2558 break;
70848515 2559
8d5d2d4c 2560 case VNC_AUTH_VENCRYPT:
3a93113a 2561 VNC_DEBUG("Accept VeNCrypt auth\n");
5fb6c7a8
AL
2562 start_auth_vencrypt(vs);
2563 break;
8d5d2d4c 2564
2f9606b3
AL
2565#ifdef CONFIG_VNC_SASL
2566 case VNC_AUTH_SASL:
2567 VNC_DEBUG("Accept SASL auth\n");
2568 start_auth_sasl(vs);
2569 break;
2570#endif /* CONFIG_VNC_SASL */
2571
70848515 2572 default: /* Should not be possible, but just in case */
7e7e2ebc 2573 VNC_DEBUG("Reject auth %d server code bug\n", vs->auth);
70848515
TS
2574 vnc_write_u8(vs, 1);
2575 if (vs->minor >= 8) {
2576 static const char err[] = "Authentication failed";
2577 vnc_write_u32(vs, sizeof(err));
2578 vnc_write(vs, err, sizeof(err));
2579 }
2580 vnc_client_error(vs);
2581 }
2582 }
2583 return 0;
2584}
2585
60fe76f3 2586static int protocol_version(VncState *vs, uint8_t *version, size_t len)
24236869
FB
2587{
2588 char local[13];
24236869
FB
2589
2590 memcpy(local, version, 12);
2591 local[12] = 0;
2592
70848515 2593 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
28a76be8
AL
2594 VNC_DEBUG("Malformed protocol version %s\n", local);
2595 vnc_client_error(vs);
2596 return 0;
24236869 2597 }
70848515
TS
2598 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2599 if (vs->major != 3 ||
28a76be8
AL
2600 (vs->minor != 3 &&
2601 vs->minor != 4 &&
2602 vs->minor != 5 &&
2603 vs->minor != 7 &&
2604 vs->minor != 8)) {
2605 VNC_DEBUG("Unsupported client version\n");
2606 vnc_write_u32(vs, VNC_AUTH_INVALID);
2607 vnc_flush(vs);
2608 vnc_client_error(vs);
2609 return 0;
70848515 2610 }
b0566f4f 2611 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
70848515
TS
2612 * as equivalent to v3.3 by servers
2613 */
b0566f4f 2614 if (vs->minor == 4 || vs->minor == 5)
28a76be8 2615 vs->minor = 3;
70848515
TS
2616
2617 if (vs->minor == 3) {
7e7e2ebc 2618 if (vs->auth == VNC_AUTH_NONE) {
70848515 2619 VNC_DEBUG("Tell client auth none\n");
7e7e2ebc 2620 vnc_write_u32(vs, vs->auth);
70848515 2621 vnc_flush(vs);
28a76be8 2622 start_client_init(vs);
7e7e2ebc 2623 } else if (vs->auth == VNC_AUTH_VNC) {
70848515 2624 VNC_DEBUG("Tell client VNC auth\n");
7e7e2ebc 2625 vnc_write_u32(vs, vs->auth);
70848515
TS
2626 vnc_flush(vs);
2627 start_auth_vnc(vs);
2628 } else {
7e7e2ebc 2629 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
70848515
TS
2630 vnc_write_u32(vs, VNC_AUTH_INVALID);
2631 vnc_flush(vs);
2632 vnc_client_error(vs);
2633 }
2634 } else {
7e7e2ebc 2635 VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
28a76be8 2636 vnc_write_u8(vs, 1); /* num auth */
7e7e2ebc 2637 vnc_write_u8(vs, vs->auth);
28a76be8
AL
2638 vnc_read_when(vs, protocol_client_auth, 1);
2639 vnc_flush(vs);
70848515 2640 }
24236869
FB
2641
2642 return 0;
2643}
2644
999342a0
CC
2645static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
2646{
2647 struct VncSurface *vs = &vd->guest;
2648
2649 return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
2650}
2651
7d964c9d
CC
2652void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
2653{
2654 int i, j;
2655
2656 w = (x + w) / VNC_STAT_RECT;
2657 h = (y + h) / VNC_STAT_RECT;
2658 x /= VNC_STAT_RECT;
2659 y /= VNC_STAT_RECT;
2660
207f328a
CC
2661 for (j = y; j <= h; j++) {
2662 for (i = x; i <= w; i++) {
7d964c9d
CC
2663 vs->lossy_rect[j][i] = 1;
2664 }
2665 }
2666}
2667
2668static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
2669{
2670 VncState *vs;
2671 int sty = y / VNC_STAT_RECT;
2672 int stx = x / VNC_STAT_RECT;
2673 int has_dirty = 0;
2674
2675 y = y / VNC_STAT_RECT * VNC_STAT_RECT;
2676 x = x / VNC_STAT_RECT * VNC_STAT_RECT;
2677
2678 QTAILQ_FOREACH(vs, &vd->clients, next) {
bc2429b9 2679 int j;
7d964c9d
CC
2680
2681 /* kernel send buffers are full -> refresh later */
2682 if (vs->output.offset) {
2683 continue;
2684 }
2685
2686 if (!vs->lossy_rect[sty][stx]) {
2687 continue;
2688 }
207f328a 2689
7d964c9d
CC
2690 vs->lossy_rect[sty][stx] = 0;
2691 for (j = 0; j < VNC_STAT_RECT; ++j) {
b4c85ddc
PL
2692 bitmap_set(vs->dirty[y + j],
2693 x / VNC_DIRTY_PIXELS_PER_BIT,
2694 VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT);
7d964c9d
CC
2695 }
2696 has_dirty++;
2697 }
207f328a 2698
7d964c9d
CC
2699 return has_dirty;
2700}
2701
2702static int vnc_update_stats(VncDisplay *vd, struct timeval * tv)
999342a0 2703{
9f64916d
GH
2704 int width = pixman_image_get_width(vd->guest.fb);
2705 int height = pixman_image_get_height(vd->guest.fb);
999342a0
CC
2706 int x, y;
2707 struct timeval res;
7d964c9d 2708 int has_dirty = 0;
999342a0 2709
9f64916d
GH
2710 for (y = 0; y < height; y += VNC_STAT_RECT) {
2711 for (x = 0; x < width; x += VNC_STAT_RECT) {
999342a0
CC
2712 VncRectStat *rect = vnc_stat_rect(vd, x, y);
2713
2714 rect->updated = false;
2715 }
2716 }
2717
ad620c29 2718 qemu_timersub(tv, &VNC_REFRESH_STATS, &res);
999342a0
CC
2719
2720 if (timercmp(&vd->guest.last_freq_check, &res, >)) {
7d964c9d 2721 return has_dirty;
999342a0
CC
2722 }
2723 vd->guest.last_freq_check = *tv;
2724
9f64916d
GH
2725 for (y = 0; y < height; y += VNC_STAT_RECT) {
2726 for (x = 0; x < width; x += VNC_STAT_RECT) {
999342a0
CC
2727 VncRectStat *rect= vnc_stat_rect(vd, x, y);
2728 int count = ARRAY_SIZE(rect->times);
2729 struct timeval min, max;
2730
2731 if (!timerisset(&rect->times[count - 1])) {
2732 continue ;
2733 }
2734
2735 max = rect->times[(rect->idx + count - 1) % count];
ad620c29 2736 qemu_timersub(tv, &max, &res);
999342a0
CC
2737
2738 if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) {
2739 rect->freq = 0;
7d964c9d 2740 has_dirty += vnc_refresh_lossy_rect(vd, x, y);
999342a0
CC
2741 memset(rect->times, 0, sizeof (rect->times));
2742 continue ;
2743 }
2744
2745 min = rect->times[rect->idx];
2746 max = rect->times[(rect->idx + count - 1) % count];
ad620c29 2747 qemu_timersub(&max, &min, &res);
999342a0
CC
2748
2749 rect->freq = res.tv_sec + res.tv_usec / 1000000.;
2750 rect->freq /= count;
2751 rect->freq = 1. / rect->freq;
2752 }
2753 }
7d964c9d 2754 return has_dirty;
999342a0
CC
2755}
2756
2757double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
2758{
2759 int i, j;
2760 double total = 0;
2761 int num = 0;
2762
2763 x = (x / VNC_STAT_RECT) * VNC_STAT_RECT;
2764 y = (y / VNC_STAT_RECT) * VNC_STAT_RECT;
2765
2766 for (j = y; j <= y + h; j += VNC_STAT_RECT) {
2767 for (i = x; i <= x + w; i += VNC_STAT_RECT) {
2768 total += vnc_stat_rect(vs->vd, i, j)->freq;
2769 num++;
2770 }
2771 }
2772
2773 if (num) {
2774 return total / num;
2775 } else {
2776 return 0;
2777 }
2778}
2779
2780static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
2781{
2782 VncRectStat *rect;
2783
2784 rect = vnc_stat_rect(vd, x, y);
2785 if (rect->updated) {
2786 return ;
2787 }
2788 rect->times[rect->idx] = *tv;
2789 rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times);
2790 rect->updated = true;
2791}
2792
1fc62412
SS
2793static int vnc_refresh_server_surface(VncDisplay *vd)
2794{
bea60dd7
PL
2795 int width = MIN(pixman_image_get_width(vd->guest.fb),
2796 pixman_image_get_width(vd->server));
2797 int height = MIN(pixman_image_get_height(vd->guest.fb),
2798 pixman_image_get_height(vd->server));
eb8934b0 2799 int cmp_bytes, server_stride, line_bytes, guest_ll, guest_stride, y = 0;
12b316d4 2800 uint8_t *guest_row0 = NULL, *server_row0;
41b4bef6 2801 VncState *vs;
1fc62412 2802 int has_dirty = 0;
9f64916d 2803 pixman_image_t *tmpbuf = NULL;
1fc62412 2804
80e0c8c3 2805 struct timeval tv = { 0, 0 };
999342a0 2806
80e0c8c3
CC
2807 if (!vd->non_adaptive) {
2808 gettimeofday(&tv, NULL);
2809 has_dirty = vnc_update_stats(vd, &tv);
2810 }
999342a0 2811
1fc62412
SS
2812 /*
2813 * Walk through the guest dirty map.
2814 * Check and copy modified bits from guest to server surface.
2815 * Update server dirty map.
2816 */
bea60dd7 2817 server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
eb8934b0
GH
2818 server_stride = guest_stride = guest_ll =
2819 pixman_image_get_stride(vd->server);
bea60dd7
PL
2820 cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES,
2821 server_stride);
9f64916d
GH
2822 if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
2823 int width = pixman_image_get_width(vd->server);
2824 tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
12b316d4 2825 } else {
eb8934b0
GH
2826 int guest_bpp =
2827 PIXMAN_FORMAT_BPP(pixman_image_get_format(vd->guest.fb));
12b316d4
PL
2828 guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
2829 guest_stride = pixman_image_get_stride(vd->guest.fb);
eb8934b0 2830 guest_ll = pixman_image_get_width(vd->guest.fb) * ((guest_bpp + 7) / 8);
12b316d4 2831 }
eb8934b0 2832 line_bytes = MIN(server_stride, guest_ll);
12b316d4 2833
12b316d4
PL
2834 for (;;) {
2835 int x;
2836 uint8_t *guest_ptr, *server_ptr;
2837 unsigned long offset = find_next_bit((unsigned long *) &vd->guest.dirty,
2838 height * VNC_DIRTY_BPL(&vd->guest),
2839 y * VNC_DIRTY_BPL(&vd->guest));
2840 if (offset == height * VNC_DIRTY_BPL(&vd->guest)) {
2841 /* no more dirty bits */
2842 break;
2843 }
2844 y = offset / VNC_DIRTY_BPL(&vd->guest);
2845 x = offset % VNC_DIRTY_BPL(&vd->guest);
1fc62412 2846
12b316d4
PL
2847 server_ptr = server_row0 + y * server_stride + x * cmp_bytes;
2848
2849 if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
2850 qemu_pixman_linebuf_fill(tmpbuf, vd->guest.fb, width, 0, y);
2851 guest_ptr = (uint8_t *)pixman_image_get_data(tmpbuf);
2852 } else {
2853 guest_ptr = guest_row0 + y * guest_stride;
2854 }
2855 guest_ptr += x * cmp_bytes;
2856
2857 for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT);
2858 x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
bea60dd7 2859 int _cmp_bytes = cmp_bytes;
12b316d4
PL
2860 if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
2861 continue;
2862 }
eb8934b0
GH
2863 if ((x + 1) * cmp_bytes > line_bytes) {
2864 _cmp_bytes = line_bytes - x * cmp_bytes;
bea60dd7 2865 }
eb8934b0 2866 assert(_cmp_bytes >= 0);
bea60dd7 2867 if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) {
12b316d4
PL
2868 continue;
2869 }
bea60dd7 2870 memcpy(server_ptr, guest_ptr, _cmp_bytes);
12b316d4
PL
2871 if (!vd->non_adaptive) {
2872 vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
2873 y, &tv);
1fc62412 2874 }
12b316d4
PL
2875 QTAILQ_FOREACH(vs, &vd->clients, next) {
2876 set_bit(x, vs->dirty[y]);
2877 }
2878 has_dirty++;
1fc62412 2879 }
12b316d4
PL
2880
2881 y++;
1fc62412 2882 }
9f64916d 2883 qemu_pixman_image_unref(tmpbuf);
1fc62412
SS
2884 return has_dirty;
2885}
2886
0f7b2864 2887static void vnc_refresh(DisplayChangeListener *dcl)
703bc68f 2888{
0f7b2864 2889 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
41b4bef6
AS
2890 VncState *vs, *vn;
2891 int has_dirty, rects = 0;
703bc68f 2892
9d6b2070
C
2893 if (QTAILQ_EMPTY(&vd->clients)) {
2894 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX);
2895 return;
2896 }
2897
1d0d59fe 2898 graphic_hw_update(vd->dcl.con);
703bc68f 2899
bd023f95 2900 if (vnc_trylock_display(vd)) {
0f7b2864 2901 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
bd023f95
CC
2902 return;
2903 }
2904
1fc62412 2905 has_dirty = vnc_refresh_server_surface(vd);
bd023f95 2906 vnc_unlock_display(vd);
1fc62412 2907
41b4bef6 2908 QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
38ee14f4 2909 rects += vnc_update_client(vs, has_dirty, false);
6185c578 2910 /* vs might be free()ed here */
703bc68f 2911 }
bd023f95 2912
2430ffe4 2913 if (has_dirty && rects) {
0f7b2864
GH
2914 vd->dcl.update_interval /= 2;
2915 if (vd->dcl.update_interval < VNC_REFRESH_INTERVAL_BASE) {
2916 vd->dcl.update_interval = VNC_REFRESH_INTERVAL_BASE;
2917 }
2430ffe4 2918 } else {
0f7b2864
GH
2919 vd->dcl.update_interval += VNC_REFRESH_INTERVAL_INC;
2920 if (vd->dcl.update_interval > VNC_REFRESH_INTERVAL_MAX) {
2921 vd->dcl.update_interval = VNC_REFRESH_INTERVAL_MAX;
2922 }
703bc68f
SS
2923 }
2924}
2925
04d2529d 2926static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
2c8cf549 2927 bool skipauth, bool websocket)
3aa3eea3 2928{
fedf0d35 2929 VncState *vs = g_new0(VncState, 1);
7d964c9d
CC
2930 int i;
2931
04d2529d
DB
2932 vs->sioc = sioc;
2933 object_ref(OBJECT(vs->sioc));
2934 vs->ioc = QIO_CHANNEL(sioc);
2935 object_ref(OBJECT(vs->ioc));
d616ccc5 2936 vs->vd = vd;
7e7e2ebc 2937
04d2529d
DB
2938 buffer_init(&vs->input, "vnc-input/%p", sioc);
2939 buffer_init(&vs->output, "vnc-output/%p", sioc);
04d2529d 2940 buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc);
543b9580 2941
04d2529d
DB
2942 buffer_init(&vs->tight.tight, "vnc-tight/%p", sioc);
2943 buffer_init(&vs->tight.zlib, "vnc-tight-zlib/%p", sioc);
2944 buffer_init(&vs->tight.gradient, "vnc-tight-gradient/%p", sioc);
543b9580 2945#ifdef CONFIG_VNC_JPEG
04d2529d 2946 buffer_init(&vs->tight.jpeg, "vnc-tight-jpeg/%p", sioc);
543b9580
GH
2947#endif
2948#ifdef CONFIG_VNC_PNG
04d2529d 2949 buffer_init(&vs->tight.png, "vnc-tight-png/%p", sioc);
543b9580 2950#endif
04d2529d
DB
2951 buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc);
2952 buffer_init(&vs->zrle.zrle, "vnc-zrle/%p", sioc);
2953 buffer_init(&vs->zrle.fb, "vnc-zrle-fb/%p", sioc);
2954 buffer_init(&vs->zrle.zlib, "vnc-zrle-zlib/%p", sioc);
543b9580 2955
7e7e2ebc
DB
2956 if (skipauth) {
2957 vs->auth = VNC_AUTH_NONE;
7e7e2ebc 2958 vs->subauth = VNC_AUTH_INVALID;
7e7e2ebc 2959 } else {
f9148c8a
DB
2960 if (websocket) {
2961 vs->auth = vd->ws_auth;
2962 vs->subauth = VNC_AUTH_INVALID;
2963 } else {
2964 vs->auth = vd->auth;
2965 vs->subauth = vd->subauth;
2966 }
7e7e2ebc 2967 }
04d2529d
DB
2968 VNC_DEBUG("Client sioc=%p ws=%d auth=%d subauth=%d\n",
2969 sioc, websocket, vs->auth, vs->subauth);
7e7e2ebc 2970
7267c094 2971 vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
7d964c9d 2972 for (i = 0; i < VNC_STAT_ROWS; ++i) {
fedf0d35 2973 vs->lossy_rect[i] = g_new0(uint8_t, VNC_STAT_COLS);
7d964c9d 2974 }
753b4053 2975
04d2529d 2976 VNC_DEBUG("New client on socket %p\n", vs->sioc);
0f7b2864 2977 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
04d2529d 2978 qio_channel_set_blocking(vs->ioc, false, NULL);
7536ee4b
TH
2979 if (websocket) {
2980 vs->websocket = 1;
f9148c8a 2981 if (vd->ws_tls) {
04d2529d
DB
2982 vs->ioc_tag = qio_channel_add_watch(
2983 vs->ioc, G_IO_IN, vncws_tls_handshake_io, vs, NULL);
3e305e4a 2984 } else {
04d2529d
DB
2985 vs->ioc_tag = qio_channel_add_watch(
2986 vs->ioc, G_IO_IN, vncws_handshake_io, vs, NULL);
0057a0d5 2987 }
04d2529d
DB
2988 } else {
2989 vs->ioc_tag = qio_channel_add_watch(
2990 vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
7536ee4b 2991 }
753b4053 2992
4a80dba3 2993 vnc_client_cache_addr(vs);
fb6ba0d5 2994 vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED);
8cf36489 2995 vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
4a80dba3 2996
8e9b0d24 2997 if (!vs->websocket) {
7536ee4b
TH
2998 vnc_init_state(vs);
2999 }
e5f34cdd
GH
3000
3001 if (vd->num_connecting > vd->connections_limit) {
3002 QTAILQ_FOREACH(vs, &vd->clients, next) {
3003 if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) {
3004 vnc_disconnect_start(vs);
3005 return;
3006 }
3007 }
3008 }
7536ee4b
TH
3009}
3010
3011void vnc_init_state(VncState *vs)
3012{
6fd8e79a 3013 vs->initialized = true;
7536ee4b 3014 VncDisplay *vd = vs->vd;
c7628bff 3015 bool first_client = QTAILQ_EMPTY(&vd->clients);
7536ee4b 3016
753b4053
AL
3017 vs->last_x = -1;
3018 vs->last_y = -1;
3019
3020 vs->as.freq = 44100;
3021 vs->as.nchannels = 2;
3022 vs->as.fmt = AUD_FMT_S16;
3023 vs->as.endianness = 0;
3024
bd023f95 3025 qemu_mutex_init(&vs->output_mutex);
175b2a6e 3026 vs->bh = qemu_bh_new(vnc_jobs_bh, vs);
bd023f95 3027
e5f34cdd 3028 QTAILQ_INSERT_TAIL(&vd->clients, vs, next);
c7628bff
GH
3029 if (first_client) {
3030 vnc_update_server_surface(vd);
3031 }
1fc62412 3032
1d0d59fe 3033 graphic_hw_update(vd->dcl.con);
1fc62412 3034
3aa3eea3
AZ
3035 vnc_write(vs, "RFB 003.008\n", 12);
3036 vnc_flush(vs);
3037 vnc_read_when(vs, protocol_version, 12);
53762ddb 3038 reset_keys(vs);
3a0558b5
GH
3039 if (vs->vd->lock_key_sync)
3040 vs->led = qemu_add_led_event_handler(kbd_leds, vs);
753b4053 3041
37c34d9d
AL
3042 vs->mouse_mode_notifier.notify = check_pointer_type_change;
3043 qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
3044
198a0039 3045 /* vs might be free()ed here */
3aa3eea3
AZ
3046}
3047
04d2529d
DB
3048static gboolean vnc_listen_io(QIOChannel *ioc,
3049 GIOCondition condition,
3050 void *opaque)
24236869 3051{
753b4053 3052 VncDisplay *vs = opaque;
04d2529d
DB
3053 QIOChannelSocket *sioc = NULL;
3054 Error *err = NULL;
24236869 3055
9f60ad50 3056 /* Catch-up */
1d0d59fe 3057 graphic_hw_update(vs->dcl.con);
04d2529d
DB
3058 sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), &err);
3059 if (sioc != NULL) {
3060 qio_channel_set_delay(QIO_CHANNEL(sioc), false);
3061 vnc_connect(vs, sioc, false,
3062 ioc != QIO_CHANNEL(vs->lsock));
3063 object_unref(OBJECT(sioc));
8e9b0d24 3064 } else {
04d2529d
DB
3065 /* client probably closed connection before we got there */
3066 error_free(err);
24236869 3067 }
7536ee4b 3068
04d2529d 3069 return TRUE;
7536ee4b 3070}
7536ee4b 3071
7c20b4a3 3072static const DisplayChangeListenerOps dcl_ops = {
34da30af
BH
3073 .dpy_name = "vnc",
3074 .dpy_refresh = vnc_refresh,
3075 .dpy_gfx_copy = vnc_dpy_copy,
3076 .dpy_gfx_update = vnc_dpy_update,
3077 .dpy_gfx_switch = vnc_dpy_switch,
3078 .dpy_gfx_check_format = qemu_pixman_check_format,
3079 .dpy_mouse_set = vnc_mouse_set,
3080 .dpy_cursor_define = vnc_dpy_cursor_define,
7c20b4a3
GH
3081};
3082
14f7143e 3083void vnc_display_init(const char *id)
24236869 3084{
4db14629
GH
3085 VncDisplay *vs;
3086
3087 if (vnc_display_find(id) != NULL) {
3088 return;
3089 }
3090 vs = g_malloc0(sizeof(*vs));
24236869 3091
14f7143e 3092 vs->id = strdup(id);
d616ccc5 3093 QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
24236869 3094
41b4bef6 3095 QTAILQ_INIT(&vs->clients);
3c9405a0 3096 vs->expires = TIME_MAX;
24236869 3097
40066175
GH
3098 if (keyboard_layout) {
3099 trace_vnc_key_map_init(keyboard_layout);
0483755a 3100 vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
40066175 3101 } else {
0483755a 3102 vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
40066175 3103 }
24236869 3104
24236869 3105 if (!vs->kbd_layout)
28a76be8 3106 exit(1);
24236869 3107
bd023f95
CC
3108 qemu_mutex_init(&vs->mutex);
3109 vnc_start_worker_thread();
bd023f95 3110
21ef45d7 3111 vs->dcl.ops = &dcl_ops;
5209089f 3112 register_displaychangelistener(&vs->dcl);
71cab5ca
TS
3113}
3114
6f43024c 3115
14f7143e 3116static void vnc_display_close(VncDisplay *vs)
71cab5ca 3117{
452b4d88
AL
3118 if (!vs)
3119 return;
bf7aa45e
GH
3120 vs->enabled = false;
3121 vs->is_unix = false;
04d2529d
DB
3122 if (vs->lsock != NULL) {
3123 if (vs->lsock_tag) {
3124 g_source_remove(vs->lsock_tag);
3125 }
3126 object_unref(OBJECT(vs->lsock));
3127 vs->lsock = NULL;
71cab5ca 3128 }
bf7aa45e 3129 vs->ws_enabled = false;
04d2529d
DB
3130 if (vs->lwebsock != NULL) {
3131 if (vs->lwebsock_tag) {
3132 g_source_remove(vs->lwebsock_tag);
3133 }
3134 object_unref(OBJECT(vs->lwebsock));
3135 vs->lwebsock = NULL;
7536ee4b 3136 }
70848515 3137 vs->auth = VNC_AUTH_INVALID;
8d5d2d4c 3138 vs->subauth = VNC_AUTH_INVALID;
3e305e4a
DB
3139 if (vs->tlscreds) {
3140 object_unparent(OBJECT(vs->tlscreds));
67c4c2bd 3141 vs->tlscreds = NULL;
3e305e4a
DB
3142 }
3143 g_free(vs->tlsaclname);
3144 vs->tlsaclname = NULL;
70848515
TS
3145}
3146
14f7143e 3147int vnc_display_password(const char *id, const char *password)
70848515 3148{
14f7143e 3149 VncDisplay *vs = vnc_display_find(id);
70848515 3150
7ef92331 3151 if (!vs) {
a6aa9d3e 3152 return -EINVAL;
7ef92331 3153 }
cf864569
GH
3154 if (vs->auth == VNC_AUTH_NONE) {
3155 error_printf_unless_qmp("If you want use passwords please enable "
3156 "password auth using '-vnc ${dpy},password'.");
3157 return -EINVAL;
1cd20f8b
AL
3158 }
3159
64641d87 3160 g_free(vs->password);
c14e9847 3161 vs->password = g_strdup(password);
a6aa9d3e
LC
3162
3163 return 0;
71cab5ca
TS
3164}
3165
14f7143e 3166int vnc_display_pw_expire(const char *id, time_t expires)
3c9405a0 3167{
14f7143e 3168 VncDisplay *vs = vnc_display_find(id);
3c9405a0 3169
1643f2b2
GH
3170 if (!vs) {
3171 return -EINVAL;
3172 }
3173
3c9405a0
GH
3174 vs->expires = expires;
3175 return 0;
3176}
3177
14f7143e 3178char *vnc_display_local_addr(const char *id)
f92f8afe 3179{
14f7143e 3180 VncDisplay *vs = vnc_display_find(id);
04d2529d
DB
3181 SocketAddress *addr;
3182 char *ret;
3183 Error *err = NULL;
d616ccc5 3184
9e0ff75e 3185 assert(vs);
04d2529d
DB
3186
3187 addr = qio_channel_socket_get_local_address(vs->lsock, &err);
3188 if (!addr) {
3189 return NULL;
3190 }
3191
3192 if (addr->type != SOCKET_ADDRESS_KIND_INET) {
3193 qapi_free_SocketAddress(addr);
3194 return NULL;
3195 }
32bafa8f
EB
3196 ret = g_strdup_printf("%s;%s", addr->u.inet.data->host,
3197 addr->u.inet.data->port);
04d2529d
DB
3198 qapi_free_SocketAddress(addr);
3199
3200 return ret;
f92f8afe
AL
3201}
3202
4db14629
GH
3203static QemuOptsList qemu_vnc_opts = {
3204 .name = "vnc",
3205 .head = QTAILQ_HEAD_INITIALIZER(qemu_vnc_opts.head),
3206 .implied_opt_name = "vnc",
3207 .desc = {
3208 {
3209 .name = "vnc",
3210 .type = QEMU_OPT_STRING,
3211 },{
3212 .name = "websocket",
3213 .type = QEMU_OPT_STRING,
3214 },{
3e305e4a
DB
3215 .name = "tls-creds",
3216 .type = QEMU_OPT_STRING,
3217 },{
3218 /* Deprecated in favour of tls-creds */
4db14629
GH
3219 .name = "x509",
3220 .type = QEMU_OPT_STRING,
3221 },{
3222 .name = "share",
3223 .type = QEMU_OPT_STRING,
1d0d59fe
GH
3224 },{
3225 .name = "display",
3226 .type = QEMU_OPT_STRING,
3227 },{
3228 .name = "head",
3229 .type = QEMU_OPT_NUMBER,
e5f34cdd
GH
3230 },{
3231 .name = "connections",
3232 .type = QEMU_OPT_NUMBER,
88428b7a
GA
3233 },{
3234 .name = "to",
3235 .type = QEMU_OPT_NUMBER,
3236 },{
3237 .name = "ipv4",
3238 .type = QEMU_OPT_BOOL,
3239 },{
3240 .name = "ipv6",
3241 .type = QEMU_OPT_BOOL,
4db14629
GH
3242 },{
3243 .name = "password",
3244 .type = QEMU_OPT_BOOL,
3245 },{
3246 .name = "reverse",
3247 .type = QEMU_OPT_BOOL,
3248 },{
3249 .name = "lock-key-sync",
3250 .type = QEMU_OPT_BOOL,
3251 },{
3252 .name = "sasl",
3253 .type = QEMU_OPT_BOOL,
3254 },{
3e305e4a 3255 /* Deprecated in favour of tls-creds */
4db14629
GH
3256 .name = "tls",
3257 .type = QEMU_OPT_BOOL,
3258 },{
3e305e4a 3259 /* Deprecated in favour of tls-creds */
4db14629 3260 .name = "x509verify",
8c7d0645 3261 .type = QEMU_OPT_STRING,
4db14629
GH
3262 },{
3263 .name = "acl",
3264 .type = QEMU_OPT_BOOL,
3265 },{
3266 .name = "lossy",
3267 .type = QEMU_OPT_BOOL,
3268 },{
3269 .name = "non-adaptive",
3270 .type = QEMU_OPT_BOOL,
3271 },
3272 { /* end of list */ }
3273 },
3274};
3275
0dd72e15 3276
3e305e4a 3277static int
0dd72e15
DB
3278vnc_display_setup_auth(VncDisplay *vs,
3279 bool password,
3280 bool sasl,
3e305e4a
DB
3281 bool websocket,
3282 Error **errp)
0dd72e15
DB
3283{
3284 /*
3285 * We have a choice of 3 authentication options
3286 *
3287 * 1. none
3288 * 2. vnc
3289 * 3. sasl
3290 *
3291 * The channel can be run in 2 modes
3292 *
3293 * 1. clear
3294 * 2. tls
3295 *
3296 * And TLS can use 2 types of credentials
3297 *
3298 * 1. anon
3299 * 2. x509
3300 *
3301 * We thus have 9 possible logical combinations
3302 *
3303 * 1. clear + none
3304 * 2. clear + vnc
3305 * 3. clear + sasl
3306 * 4. tls + anon + none
3307 * 5. tls + anon + vnc
3308 * 6. tls + anon + sasl
3309 * 7. tls + x509 + none
3310 * 8. tls + x509 + vnc
3311 * 9. tls + x509 + sasl
3312 *
3313 * These need to be mapped into the VNC auth schemes
3314 * in an appropriate manner. In regular VNC, all the
3315 * TLS options get mapped into VNC_AUTH_VENCRYPT
3316 * sub-auth types.
f9148c8a
DB
3317 *
3318 * In websockets, the https:// protocol already provides
3319 * TLS support, so there is no need to make use of the
3320 * VeNCrypt extension. Furthermore, websockets browser
3321 * clients could not use VeNCrypt even if they wanted to,
3322 * as they cannot control when the TLS handshake takes
3323 * place. Thus there is no option but to rely on https://,
3324 * meaning combinations 4->6 and 7->9 will be mapped to
3325 * VNC auth schemes in the same way as combos 1->3.
3326 *
3327 * Regardless of fact that we have a different mapping to
3328 * VNC auth mechs for plain VNC vs websockets VNC, the end
3329 * result has the same security characteristics.
0dd72e15
DB
3330 */
3331 if (password) {
3e305e4a 3332 if (vs->tlscreds) {
0dd72e15 3333 vs->auth = VNC_AUTH_VENCRYPT;
f9148c8a
DB
3334 if (websocket) {
3335 vs->ws_tls = true;
3336 }
3e305e4a
DB
3337 if (object_dynamic_cast(OBJECT(vs->tlscreds),
3338 TYPE_QCRYPTO_TLS_CREDS_X509)) {
0dd72e15
DB
3339 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
3340 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
3e305e4a
DB
3341 } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
3342 TYPE_QCRYPTO_TLS_CREDS_ANON)) {
0dd72e15
DB
3343 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
3344 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
3e305e4a
DB
3345 } else {
3346 error_setg(errp,
3347 "Unsupported TLS cred type %s",
3348 object_get_typename(OBJECT(vs->tlscreds)));
3349 return -1;
0dd72e15
DB
3350 }
3351 } else {
3352 VNC_DEBUG("Initializing VNC server with password auth\n");
3353 vs->auth = VNC_AUTH_VNC;
3354 vs->subauth = VNC_AUTH_INVALID;
3355 }
f9148c8a
DB
3356 if (websocket) {
3357 vs->ws_auth = VNC_AUTH_VNC;
3358 } else {
3359 vs->ws_auth = VNC_AUTH_INVALID;
3360 }
0dd72e15 3361 } else if (sasl) {
3e305e4a 3362 if (vs->tlscreds) {
0dd72e15 3363 vs->auth = VNC_AUTH_VENCRYPT;
f9148c8a
DB
3364 if (websocket) {
3365 vs->ws_tls = true;
3366 }
3e305e4a
DB
3367 if (object_dynamic_cast(OBJECT(vs->tlscreds),
3368 TYPE_QCRYPTO_TLS_CREDS_X509)) {
0dd72e15
DB
3369 VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
3370 vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
3e305e4a
DB
3371 } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
3372 TYPE_QCRYPTO_TLS_CREDS_ANON)) {
0dd72e15
DB
3373 VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
3374 vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
3e305e4a
DB
3375 } else {
3376 error_setg(errp,
3377 "Unsupported TLS cred type %s",
3378 object_get_typename(OBJECT(vs->tlscreds)));
3379 return -1;
0dd72e15
DB
3380 }
3381 } else {
3382 VNC_DEBUG("Initializing VNC server with SASL auth\n");
3383 vs->auth = VNC_AUTH_SASL;
3384 vs->subauth = VNC_AUTH_INVALID;
3385 }
f9148c8a
DB
3386 if (websocket) {
3387 vs->ws_auth = VNC_AUTH_SASL;
3388 } else {
3389 vs->ws_auth = VNC_AUTH_INVALID;
3390 }
0dd72e15 3391 } else {
3e305e4a 3392 if (vs->tlscreds) {
0dd72e15 3393 vs->auth = VNC_AUTH_VENCRYPT;
f9148c8a
DB
3394 if (websocket) {
3395 vs->ws_tls = true;
3396 }
3e305e4a
DB
3397 if (object_dynamic_cast(OBJECT(vs->tlscreds),
3398 TYPE_QCRYPTO_TLS_CREDS_X509)) {
0dd72e15
DB
3399 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
3400 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
3e305e4a
DB
3401 } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
3402 TYPE_QCRYPTO_TLS_CREDS_ANON)) {
0dd72e15
DB
3403 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
3404 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
3e305e4a
DB
3405 } else {
3406 error_setg(errp,
3407 "Unsupported TLS cred type %s",
3408 object_get_typename(OBJECT(vs->tlscreds)));
3409 return -1;
0dd72e15
DB
3410 }
3411 } else {
3412 VNC_DEBUG("Initializing VNC server with no auth\n");
3413 vs->auth = VNC_AUTH_NONE;
3414 vs->subauth = VNC_AUTH_INVALID;
3415 }
f9148c8a
DB
3416 if (websocket) {
3417 vs->ws_auth = VNC_AUTH_NONE;
3418 } else {
3419 vs->ws_auth = VNC_AUTH_INVALID;
3420 }
0dd72e15 3421 }
3e305e4a
DB
3422 return 0;
3423}
3424
3425
3426/*
3427 * Handle back compat with old CLI syntax by creating some
3428 * suitable QCryptoTLSCreds objects
3429 */
3430static QCryptoTLSCreds *
3431vnc_display_create_creds(bool x509,
3432 bool x509verify,
3433 const char *dir,
3434 const char *id,
3435 Error **errp)
3436{
3437 gchar *credsid = g_strdup_printf("tlsvnc%s", id);
3438 Object *parent = object_get_objects_root();
3439 Object *creds;
3440 Error *err = NULL;
3441
3442 if (x509) {
3443 creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_X509,
3444 parent,
3445 credsid,
3446 &err,
3447 "endpoint", "server",
3448 "dir", dir,
3449 "verify-peer", x509verify ? "yes" : "no",
3450 NULL);
3451 } else {
3452 creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON,
3453 parent,
3454 credsid,
3455 &err,
3456 "endpoint", "server",
3457 NULL);
3458 }
3459
3460 g_free(credsid);
3461
3462 if (err) {
3463 error_propagate(errp, err);
3464 return NULL;
3465 }
3466
3467 return QCRYPTO_TLS_CREDS(creds);
0dd72e15
DB
3468}
3469
3e305e4a 3470
4db14629 3471void vnc_display_open(const char *id, Error **errp)
71cab5ca 3472{
14f7143e 3473 VncDisplay *vs = vnc_display_find(id);
4db14629 3474 QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
e0d03b8c 3475 SocketAddress *saddr = NULL, *wsaddr = NULL;
e2a11d9d 3476 const char *share, *device_id;
1d0d59fe 3477 QemuConsole *con;
a2c72de0
GA
3478 bool password = false;
3479 bool reverse = false;
e2a11d9d 3480 const char *vnc;
e5560329 3481 char *h;
3e305e4a 3482 const char *credid;
a2c72de0 3483 bool sasl = false;
d169f04b 3484#ifdef CONFIG_VNC_SASL
2f9606b3
AL
3485 int saslErr;
3486#endif
76655d6d 3487 int acl = 0;
3a0558b5 3488 int lock_key_sync = 1;
71cab5ca 3489
d616ccc5 3490 if (!vs) {
2d55f0e8
PB
3491 error_setg(errp, "VNC display not active");
3492 return;
3493 }
14f7143e 3494 vnc_display_close(vs);
24236869 3495
4db14629
GH
3496 if (!opts) {
3497 return;
3498 }
e2a11d9d
GA
3499 vnc = qemu_opt_get(opts, "vnc");
3500 if (!vnc || strcmp(vnc, "none") == 0) {
4db14629
GH
3501 return;
3502 }
e2a11d9d 3503
e5560329
GH
3504 h = strrchr(vnc, ':');
3505 if (h) {
274c3b52
JT
3506 size_t hlen = h - vnc;
3507
e0d03b8c
DB
3508 const char *websocket = qemu_opt_get(opts, "websocket");
3509 int to = qemu_opt_get_number(opts, "to", 0);
3f0230e9
DB
3510 bool has_ipv4 = qemu_opt_get(opts, "ipv4");
3511 bool has_ipv6 = qemu_opt_get(opts, "ipv6");
3512 bool ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
3513 bool ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
e0d03b8c
DB
3514
3515 saddr = g_new0(SocketAddress, 1);
3516 if (websocket) {
3517 if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
3518 error_setg(errp,
3519 "SHA1 hash support is required for websockets");
3520 goto fail;
3521 }
3522
3523 wsaddr = g_new0(SocketAddress, 1);
3524 vs->ws_enabled = true;
3525 }
3526
3527 if (strncmp(vnc, "unix:", 5) == 0) {
2d32adda 3528 saddr->type = SOCKET_ADDRESS_KIND_UNIX;
32bafa8f
EB
3529 saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
3530 saddr->u.q_unix.data->path = g_strdup(vnc + 5);
e0d03b8c
DB
3531
3532 if (vs->ws_enabled) {
3533 error_setg(errp, "UNIX sockets not supported with websock");
3534 goto fail;
3535 }
274c3b52 3536 } else {
e0d03b8c 3537 unsigned long long baseport;
0399293e 3538 InetSocketAddress *inet;
2d32adda 3539 saddr->type = SOCKET_ADDRESS_KIND_INET;
32bafa8f 3540 inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
e0d03b8c 3541 if (vnc[0] == '[' && vnc[hlen - 1] == ']') {
0399293e 3542 inet->host = g_strndup(vnc + 1, hlen - 2);
e0d03b8c 3543 } else {
0399293e 3544 inet->host = g_strndup(vnc, hlen);
e0d03b8c
DB
3545 }
3546 if (parse_uint_full(h + 1, &baseport, 10) < 0) {
3547 error_setg(errp, "can't convert to a number: %s", h + 1);
3548 goto fail;
3549 }
3550 if (baseport > 65535 ||
3551 baseport + 5900 > 65535) {
3552 error_setg(errp, "port %s out of range", h + 1);
3553 goto fail;
3554 }
0399293e 3555 inet->port = g_strdup_printf(
e0d03b8c
DB
3556 "%d", (int)baseport + 5900);
3557
3558 if (to) {
0399293e
EB
3559 inet->has_to = true;
3560 inet->to = to + 5900;
e0d03b8c 3561 }
0399293e
EB
3562 inet->ipv4 = ipv4;
3563 inet->has_ipv4 = has_ipv4;
3564 inet->ipv6 = ipv6;
3565 inet->has_ipv6 = has_ipv6;
e0d03b8c
DB
3566
3567 if (vs->ws_enabled) {
2d32adda 3568 wsaddr->type = SOCKET_ADDRESS_KIND_INET;
32bafa8f
EB
3569 inet = wsaddr->u.inet.data = g_new0(InetSocketAddress, 1);
3570 inet->host = g_strdup(saddr->u.inet.data->host);
0399293e 3571 inet->port = g_strdup(websocket);
e0d03b8c
DB
3572
3573 if (to) {
0399293e
EB
3574 inet->has_to = true;
3575 inet->to = to;
e0d03b8c 3576 }
0399293e
EB
3577 inet->ipv4 = ipv4;
3578 inet->has_ipv4 = has_ipv4;
3579 inet->ipv6 = ipv6;
3580 inet->has_ipv6 = has_ipv6;
e0d03b8c 3581 }
274c3b52 3582 }
e5560329
GH
3583 } else {
3584 error_setg(errp, "no vnc port specified");
3585 goto fail;
e2a11d9d 3586 }
e5560329 3587
4db14629 3588 password = qemu_opt_get_bool(opts, "password", false);
800567a6
DB
3589 if (password) {
3590 if (fips_get_state()) {
3591 error_setg(errp,
3592 "VNC password auth disabled due to FIPS mode, "
3593 "consider using the VeNCrypt or SASL authentication "
3594 "methods as an alternative");
3595 goto fail;
3596 }
3597 if (!qcrypto_cipher_supports(
3598 QCRYPTO_CIPHER_ALG_DES_RFB)) {
3599 error_setg(errp,
3600 "Cipher backend does not support DES RFB algorithm");
3601 goto fail;
3602 }
4db14629
GH
3603 }
3604
3605 reverse = qemu_opt_get_bool(opts, "reverse", false);
3606 lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true);
4db14629 3607 sasl = qemu_opt_get_bool(opts, "sasl", false);
d169f04b
DB
3608#ifndef CONFIG_VNC_SASL
3609 if (sasl) {
3610 error_setg(errp, "VNC SASL auth requires cyrus-sasl support");
3611 goto fail;
3612 }
3613#endif /* CONFIG_VNC_SASL */
3e305e4a
DB
3614 credid = qemu_opt_get(opts, "tls-creds");
3615 if (credid) {
3616 Object *creds;
3617 if (qemu_opt_get(opts, "tls") ||
3618 qemu_opt_get(opts, "x509") ||
3619 qemu_opt_get(opts, "x509verify")) {
3620 error_setg(errp,
c62e90af 3621 "'tls-creds' parameter is mutually exclusive with "
3e305e4a 3622 "'tls', 'x509' and 'x509verify' parameters");
4db14629
GH
3623 goto fail;
3624 }
3e305e4a
DB
3625
3626 creds = object_resolve_path_component(
3627 object_get_objects_root(), credid);
3628 if (!creds) {
3629 error_setg(errp, "No TLS credentials with id '%s'",
3630 credid);
3631 goto fail;
3632 }
3633 vs->tlscreds = (QCryptoTLSCreds *)
3634 object_dynamic_cast(creds,
3635 TYPE_QCRYPTO_TLS_CREDS);
3636 if (!vs->tlscreds) {
3637 error_setg(errp, "Object with id '%s' is not TLS credentials",
3638 credid);
3639 goto fail;
3640 }
3641 object_ref(OBJECT(vs->tlscreds));
3642
3643 if (vs->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
3644 error_setg(errp,
3645 "Expecting TLS credentials with a server endpoint");
3646 goto fail;
3647 }
3648 } else {
3649 const char *path;
3650 bool tls = false, x509 = false, x509verify = false;
3651 tls = qemu_opt_get_bool(opts, "tls", false);
3652 if (tls) {
3653 path = qemu_opt_get(opts, "x509");
3654
3655 if (path) {
3656 x509 = true;
3657 } else {
3658 path = qemu_opt_get(opts, "x509verify");
3659 if (path) {
3660 x509 = true;
3661 x509verify = true;
3662 }
3663 }
3664 vs->tlscreds = vnc_display_create_creds(x509,
3665 x509verify,
3666 path,
3667 vs->id,
3668 errp);
3669 if (!vs->tlscreds) {
3670 goto fail;
3671 }
3672 }
4db14629 3673 }
4db14629 3674 acl = qemu_opt_get_bool(opts, "acl", false);
4db14629
GH
3675
3676 share = qemu_opt_get(opts, "share");
3677 if (share) {
3678 if (strcmp(share, "ignore") == 0) {
3679 vs->share_policy = VNC_SHARE_POLICY_IGNORE;
3680 } else if (strcmp(share, "allow-exclusive") == 0) {
3681 vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
3682 } else if (strcmp(share, "force-shared") == 0) {
3683 vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
3684 } else {
3685 error_setg(errp, "unknown vnc share= option");
3686 goto fail;
3687 }
3688 } else {
3689 vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
3690 }
e5f34cdd 3691 vs->connections_limit = qemu_opt_get_number(opts, "connections", 32);
4db14629 3692
4db14629
GH
3693#ifdef CONFIG_VNC_JPEG
3694 vs->lossy = qemu_opt_get_bool(opts, "lossy", false);
3695#endif
3696 vs->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false);
e22492d3
PL
3697 /* adaptive updates are only used with tight encoding and
3698 * if lossy updates are enabled so we can disable all the
3699 * calculations otherwise */
3700 if (!vs->lossy) {
3701 vs->non_adaptive = true;
3702 }
3703
3e305e4a 3704 if (acl) {
c8496408 3705 if (strcmp(vs->id, "default") == 0) {
3e305e4a 3706 vs->tlsaclname = g_strdup("vnc.x509dname");
c8496408 3707 } else {
3e305e4a 3708 vs->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vs->id);
c8496408 3709 }
3e305e4a 3710 qemu_acl_init(vs->tlsaclname);
2cc45228 3711 }
76655d6d
AL
3712#ifdef CONFIG_VNC_SASL
3713 if (acl && sasl) {
c8496408
GH
3714 char *aclname;
3715
3716 if (strcmp(vs->id, "default") == 0) {
3717 aclname = g_strdup("vnc.username");
3718 } else {
3719 aclname = g_strdup_printf("vnc.%s.username", vs->id);
3720 }
3721 vs->sasl.acl = qemu_acl_init(aclname);
c8496408 3722 g_free(aclname);
76655d6d
AL
3723 }
3724#endif
3725
e0d03b8c 3726 if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) {
3e305e4a
DB
3727 goto fail;
3728 }
24236869 3729
2f9606b3
AL
3730#ifdef CONFIG_VNC_SASL
3731 if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
2d55f0e8
PB
3732 error_setg(errp, "Failed to initialize SASL auth: %s",
3733 sasl_errstring(saslErr, NULL, NULL));
1ce52c78 3734 goto fail;
2f9606b3
AL
3735 }
3736#endif
3a0558b5 3737 vs->lock_key_sync = lock_key_sync;
2f9606b3 3738
1d0d59fe
GH
3739 device_id = qemu_opt_get(opts, "display");
3740 if (device_id) {
1d0d59fe 3741 int head = qemu_opt_get_number(opts, "head", 0);
f2c1d54c 3742 Error *err = NULL;
1d0d59fe 3743
f2c1d54c
GH
3744 con = qemu_console_lookup_by_device_name(device_id, head, &err);
3745 if (err) {
3746 error_propagate(errp, err);
1d0d59fe
GH
3747 goto fail;
3748 }
3749 } else {
3750 con = NULL;
3751 }
3752
3753 if (con != vs->dcl.con) {
3754 unregister_displaychangelistener(&vs->dcl);
3755 vs->dcl.con = con;
3756 register_displaychangelistener(&vs->dcl);
3757 }
3758
3aa3eea3 3759 if (reverse) {
9712ecaf 3760 /* connect to viewer */
04d2529d
DB
3761 QIOChannelSocket *sioc = NULL;
3762 vs->lsock = NULL;
3763 vs->lwebsock = NULL;
e0d03b8c
DB
3764 if (vs->ws_enabled) {
3765 error_setg(errp, "Cannot use websockets in reverse mode");
3766 goto fail;
3aa3eea3 3767 }
04d2529d
DB
3768 vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
3769 sioc = qio_channel_socket_new();
3770 if (qio_channel_socket_connect_sync(sioc, saddr, errp) < 0) {
007fcd3e
PB
3771 goto fail;
3772 }
04d2529d
DB
3773 vnc_connect(vs, sioc, false, false);
3774 object_unref(OBJECT(sioc));
9712ecaf 3775 } else {
04d2529d
DB
3776 vs->lsock = qio_channel_socket_new();
3777 if (qio_channel_socket_listen_sync(vs->lsock, saddr, errp) < 0) {
e0d03b8c
DB
3778 goto fail;
3779 }
2d32adda 3780 vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
04d2529d
DB
3781 vs->enabled = true;
3782
e0d03b8c 3783 if (vs->ws_enabled) {
04d2529d
DB
3784 vs->lwebsock = qio_channel_socket_new();
3785 if (qio_channel_socket_listen_sync(vs->lwebsock,
3786 wsaddr, errp) < 0) {
3787 object_unref(OBJECT(vs->lsock));
3788 vs->lsock = NULL;
e0d03b8c 3789 goto fail;
7536ee4b 3790 }
9712ecaf 3791 }
04d2529d
DB
3792
3793 vs->lsock_tag = qio_channel_add_watch(
3794 QIO_CHANNEL(vs->lsock),
3795 G_IO_IN, vnc_listen_io, vs, NULL);
bf7aa45e 3796 if (vs->ws_enabled) {
04d2529d
DB
3797 vs->lwebsock_tag = qio_channel_add_watch(
3798 QIO_CHANNEL(vs->lwebsock),
3799 G_IO_IN, vnc_listen_io, vs, NULL);
7536ee4b 3800 }
24236869 3801 }
e0d03b8c
DB
3802
3803 qapi_free_SocketAddress(saddr);
3804 qapi_free_SocketAddress(wsaddr);
2d55f0e8 3805 return;
1ce52c78
PB
3806
3807fail:
e0d03b8c
DB
3808 qapi_free_SocketAddress(saddr);
3809 qapi_free_SocketAddress(wsaddr);
bf7aa45e 3810 vs->enabled = false;
bf7aa45e 3811 vs->ws_enabled = false;
24236869 3812}
13661089 3813
14f7143e 3814void vnc_display_add_client(const char *id, int csock, bool skipauth)
13661089 3815{
14f7143e 3816 VncDisplay *vs = vnc_display_find(id);
04d2529d 3817 QIOChannelSocket *sioc;
13661089 3818
d616ccc5
GH
3819 if (!vs) {
3820 return;
3821 }
04d2529d
DB
3822
3823 sioc = qio_channel_socket_new_fd(csock, NULL);
3824 if (sioc) {
3825 vnc_connect(vs, sioc, skipauth, false);
3826 object_unref(OBJECT(sioc));
3827 }
13661089 3828}
4db14629 3829
9634f4e3 3830static void vnc_auto_assign_id(QemuOptsList *olist, QemuOpts *opts)
2779672f
GA
3831{
3832 int i = 2;
3833 char *id;
3834
3835 id = g_strdup("default");
3836 while (qemu_opts_find(olist, id)) {
3837 g_free(id);
3838 id = g_strdup_printf("vnc%d", i++);
3839 }
3840 qemu_opts_set_id(opts, id);
3841}
3842
70b94331 3843QemuOpts *vnc_parse(const char *str, Error **errp)
4db14629 3844{
4db14629 3845 QemuOptsList *olist = qemu_find_opts("vnc");
70b94331 3846 QemuOpts *opts = qemu_opts_parse(olist, str, true, errp);
81607cbf 3847 const char *id;
4db14629 3848
81607cbf
GA
3849 if (!opts) {
3850 return NULL;
3851 }
3852
3853 id = qemu_opts_id(opts);
4db14629
GH
3854 if (!id) {
3855 /* auto-assign id if not present */
2779672f 3856 vnc_auto_assign_id(olist, opts);
4db14629 3857 }
9634f4e3
GH
3858 return opts;
3859}
3860
28d0de7a 3861int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
9634f4e3
GH
3862{
3863 Error *local_err = NULL;
3864 char *id = (char *)qemu_opts_id(opts);
4db14629 3865
9634f4e3 3866 assert(id);
4db14629
GH
3867 vnc_display_init(id);
3868 vnc_display_open(id, &local_err);
3869 if (local_err != NULL) {
c29b77f9 3870 error_reportf_err(local_err, "Failed to start VNC server: ");
4db14629
GH
3871 exit(1);
3872 }
3873 return 0;
3874}
3875
3876static void vnc_register_config(void)
3877{
3878 qemu_add_opts(&qemu_vnc_opts);
3879}
34294e2f 3880opts_init(vnc_register_config);