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