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