blob: f20c08db4a2dd0bdbb80b607f585b16140c0320c [file] [log] [blame]
bellard7d510b82006-05-01 10:38:19 +00001/*
2 * QEMU VNC display driver
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard7d510b82006-05-01 10:38:19 +00004 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5 * Copyright (C) 2006 Fabrice Bellard
aliguori19a490b2009-03-06 20:27:13 +00006 * Copyright (C) 2009 Red Hat, Inc
ths5fafdf22007-09-16 21:08:06 +00007 *
bellard7d510b82006-05-01 10:38:19 +00008 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
aliguori19a490b2009-03-06 20:27:13 +000027#include "vnc.h"
Corentin Charybd023f92010-07-07 20:58:02 +020028#include "vnc-jobs.h"
Gerd Hoffmann40066172014-05-21 13:18:20 +020029#include "trace.h"
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +020030#include "hw/qdev.h"
Paolo Bonzini9c17d612012-12-17 18:20:04 +010031#include "sysemu/sysemu.h"
Markus Armbrusterd49b6832015-03-17 18:29:20 +010032#include "qemu/error-report.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010033#include "qemu/sockets.h"
34#include "qemu/timer.h"
35#include "qemu/acl.h"
Gerd Hoffmann4db14622014-09-16 12:33:03 +020036#include "qemu/config-file.h"
Markus Armbrustercc7a8ea2015-03-17 17:22:46 +010037#include "qapi/qmp/qerror.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010038#include "qapi/qmp/types.h"
Luiz Capitulino2b54aa82011-10-17 16:41:22 -020039#include "qmp-commands.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010040#include "qemu/osdep.h"
Gerd Hoffmann8d447d12013-12-02 14:27:18 +010041#include "ui/input.h"
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +020042#include "qapi-event.h"
Daniel P. Berrange8e9b0d22015-07-01 18:10:36 +010043#include "crypto/hash.h"
Daniel P. Berrange3e305e42015-08-06 14:39:32 +010044#include "crypto/tlscredsanon.h"
45#include "crypto/tlscredsx509.h"
46#include "qom/object_interfaces.h"
bellard24236862006-04-30 21:28:36 +000047
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +010048#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
Stefano Stabellini2430ffe2009-08-03 10:56:01 +010049#define VNC_REFRESH_INTERVAL_INC 50
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +010050#define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE
Corentin Chary999342a2011-02-04 09:05:55 +010051static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
52static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
bellard24236862006-04-30 21:28:36 +000053
54#include "vnc_keysym.h"
Daniel P. Berrange800567a2015-07-01 18:10:38 +010055#include "crypto/cipher.h"
ths70848512007-08-25 01:37:05 +000056
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +020057static QTAILQ_HEAD(, VncDisplay) vnc_displays =
58 QTAILQ_HEAD_INITIALIZER(vnc_displays);
bellarda9ce8592007-02-05 20:20:30 +000059
Gerd Hoffmannd467b672010-05-21 11:54:34 +020060static int vnc_cursor_define(VncState *vs);
Gerd Hoffmann7bc93182012-02-08 13:18:37 +010061static void vnc_release_modifiers(VncState *vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +020062
Gerd Hoffmann8cf36482011-11-24 18:10:49 +010063static 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
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +020077 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:
Gerd Hoffmann8cf36482011-11-24 18:10:49 +010085 vs->vd->num_exclusive--;
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +020086 break;
87 default:
88 break;
Gerd Hoffmann8cf36482011-11-24 18:10:49 +010089 }
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +020090
Gerd Hoffmann8cf36482011-11-24 18:10:49 +010091 vs->share_mode = mode;
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +020092
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:
Gerd Hoffmann8cf36482011-11-24 18:10:49 +0100101 vs->vd->num_exclusive++;
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +0200102 break;
103 default:
104 break;
Gerd Hoffmann8cf36482011-11-24 18:10:49 +0100105 }
106}
107
aliguori1ff7df12009-03-06 20:27:05 +0000108static 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;
aliguori457772e2009-03-13 15:03:27 +0000115 size_t addrlen;
aliguori1ff7df12009-03-06 20:27:05 +0000116
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
aliguori457772e2009-03-13 15:03:27 +0000126 /* Enough for the existing format + the 2 vars we're
Stefan Weilf425c272009-06-06 17:00:31 +0200127 * substituting in. */
aliguori457772e2009-03-13 15:03:27 +0000128 addrlen = strlen(format) + strlen(host) + strlen(serv);
Anthony Liguori7267c092011-08-20 22:09:37 -0500129 addr = g_malloc(addrlen + 1);
aliguori457772e2009-03-13 15:03:27 +0000130 snprintf(addr, addrlen, format, host, serv);
131 addr[addrlen] = '\0';
aliguori1ff7df12009-03-06 20:27:05 +0000132
133 return addr;
134}
135
aliguori2f9606b2009-03-06 20:27:28 +0000136
137char *vnc_socket_local_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +0000138 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
aliguori2f9606b2009-03-06 20:27:28 +0000148char *vnc_socket_remote_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +0000149 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
Eric Blake98481bf2015-10-26 16:34:45 -0600159static void vnc_init_basic_info(struct sockaddr_storage *sa,
160 socklen_t salen,
161 VncBasicInfo *info,
162 Error **errp)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200163{
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) {
Eric Blake98481bf2015-10-26 16:34:45 -0600172 error_setg(errp, "Cannot resolve address: %s",
173 gai_strerror(err));
174 return;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200175 }
176
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200177 info->host = g_strdup(host);
178 info->service = g_strdup(serv);
179 info->family = inet_netfamily(sa->ss_family);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200180}
181
Eric Blake98481bf2015-10-26 16:34:45 -0600182static void vnc_init_basic_info_from_server_addr(int fd, VncBasicInfo *info,
183 Error **errp)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200184{
185 struct sockaddr_storage sa;
186 socklen_t salen;
187
188 salen = sizeof(sa);
189 if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
Eric Blake98481bf2015-10-26 16:34:45 -0600190 error_setg_errno(errp, errno, "getsockname failed");
191 return;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200192 }
193
Eric Blake98481bf2015-10-26 16:34:45 -0600194 vnc_init_basic_info(&sa, salen, info, errp);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200195}
196
Eric Blake98481bf2015-10-26 16:34:45 -0600197static void vnc_init_basic_info_from_remote_addr(int fd, VncBasicInfo *info,
198 Error **errp)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200199{
200 struct sockaddr_storage sa;
201 socklen_t salen;
202
203 salen = sizeof(sa);
204 if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
Eric Blake98481bf2015-10-26 16:34:45 -0600205 error_setg_errno(errp, errno, "getpeername failed");
206 return;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200207 }
208
Eric Blake98481bf2015-10-26 16:34:45 -0600209 vnc_init_basic_info(&sa, salen, info, errp);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200210}
211
aliguori1ff7df12009-03-06 20:27:05 +0000212static 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:
aliguori1ff7df12009-03-06 20:27:05 +0000231 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";
aliguori28a76be2009-03-06 20:27:40 +0000246 case VNC_AUTH_VENCRYPT_TLSSASL:
247 return "vencrypt+tls+sasl";
248 case VNC_AUTH_VENCRYPT_X509SASL:
249 return "vencrypt+x509+sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000250 default:
251 return "vencrypt";
252 }
aliguori2f9606b2009-03-06 20:27:28 +0000253 case VNC_AUTH_SASL:
aliguori28a76be2009-03-06 20:27:40 +0000254 return "sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000255 }
256 return "unknown";
257}
258
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +0200259static VncServerInfo *vnc_server_info_get(VncDisplay *vd)
Luiz Capitulinoa7789382010-01-14 14:50:53 -0200260{
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200261 VncServerInfo *info;
Eric Blake98481bf2015-10-26 16:34:45 -0600262 Error *err = NULL;
Luiz Capitulinoa7789382010-01-14 14:50:53 -0200263
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200264 info = g_malloc(sizeof(*info));
Eric Blakeddf21902015-10-26 16:34:49 -0600265 vnc_init_basic_info_from_server_addr(vd->lsock,
266 qapi_VncServerInfo_base(info), &err);
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200267 info->has_auth = true;
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +0200268 info->auth = g_strdup(vnc_auth_name(vd));
Eric Blake98481bf2015-10-26 16:34:45 -0600269 if (err) {
270 qapi_free_VncServerInfo(info);
271 info = NULL;
272 error_free(err);
273 }
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200274 return info;
Luiz Capitulinoa7789382010-01-14 14:50:53 -0200275}
276
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200277static void vnc_client_cache_auth(VncState *client)
aliguori1ff7df12009-03-06 20:27:05 +0000278{
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200279 if (!client->info) {
280 return;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200281 }
aliguori1263b7d2009-03-06 20:27:32 +0000282
Daniel P. Berrange3e305e42015-08-06 14:39:32 +0100283 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;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200288 }
aliguori1263b7d2009-03-06 20:27:32 +0000289#ifdef CONFIG_VNC_SASL
290 if (client->sasl.conn &&
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200291 client->sasl.username) {
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200292 client->info->has_sasl_username = true;
293 client->info->sasl_username = g_strdup(client->sasl.username);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200294 }
295#endif
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200296}
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200297
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200298static void vnc_client_cache_addr(VncState *client)
299{
Eric Blake98481bf2015-10-26 16:34:45 -0600300 Error *err = NULL;
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200301
Eric Blake98481bf2015-10-26 16:34:45 -0600302 client->info = g_malloc0(sizeof(*client->info));
Eric Blakeddf21902015-10-26 16:34:49 -0600303 vnc_init_basic_info_from_remote_addr(client->csock,
304 qapi_VncClientInfo_base(client->info),
Eric Blake98481bf2015-10-26 16:34:45 -0600305 &err);
306 if (err) {
307 qapi_free_VncClientInfo(client->info);
308 client->info = NULL;
309 error_free(err);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200310 }
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200311}
312
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200313static void vnc_qmp_event(VncState *vs, QAPIEvent event)
Luiz Capitulino586153d2010-01-14 14:50:57 -0200314{
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200315 VncServerInfo *si;
Luiz Capitulino586153d2010-01-14 14:50:57 -0200316
317 if (!vs->info) {
318 return;
319 }
320
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +0200321 si = vnc_server_info_get(vs->vd);
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200322 if (!si) {
Luiz Capitulino586153d2010-01-14 14:50:57 -0200323 return;
324 }
325
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200326 switch (event) {
327 case QAPI_EVENT_VNC_CONNECTED:
Eric Blakeddf21902015-10-26 16:34:49 -0600328 qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info),
329 &error_abort);
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200330 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 }
Luiz Capitulino586153d2010-01-14 14:50:57 -0200340
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200341 qapi_free_VncServerInfo(si);
Luiz Capitulino586153d2010-01-14 14:50:57 -0200342}
343
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200344static VncClientInfo *qmp_query_vnc_client(const VncState *client)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200345{
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200346 struct sockaddr_storage sa;
347 socklen_t salen = sizeof(sa);
348 char host[NI_MAXHOST];
349 char serv[NI_MAXSERV];
350 VncClientInfo *info;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200351
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200352 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 }
362
363 info = g_malloc0(sizeof(*info));
Eric Blakeddf21902015-10-26 16:34:49 -0600364 info->host = g_strdup(host);
365 info->service = g_strdup(serv);
366 info->family = inet_netfamily(sa.ss_family);
367 info->websocket = client->websocket;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200368
Daniel P. Berrange3e305e42015-08-06 14:39:32 +0100369 if (client->tls) {
370 info->x509_dname = qcrypto_tls_session_get_peer_name(client->tls);
371 info->has_x509_dname = info->x509_dname != NULL;
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200372 }
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200373#ifdef CONFIG_VNC_SASL
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200374 if (client->sasl.conn && client->sasl.username) {
375 info->has_sasl_username = true;
376 info->sasl_username = g_strdup(client->sasl.username);
377 }
aliguori1263b7d2009-03-06 20:27:32 +0000378#endif
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200379
380 return info;
aliguori1ff7df12009-03-06 20:27:05 +0000381}
382
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +0200383static 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
Gerd Hoffmann2d29a432014-12-09 15:27:39 +0100398static 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
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200412VncInfo *qmp_query_vnc(Error **errp)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200413{
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200414 VncInfo *info = g_malloc0(sizeof(*info));
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +0200415 VncDisplay *vd = vnc_display_find(NULL);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200416
Gerd Hoffmannbf7aa452015-02-19 10:46:49 +0100417 if (vd == NULL || !vd->enabled) {
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200418 info->enabled = false;
aliguori1ff7df12009-03-06 20:27:05 +0000419 } else {
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200420 struct sockaddr_storage sa;
421 socklen_t salen = sizeof(sa);
422 char host[NI_MAXHOST];
423 char serv[NI_MAXSERV];
bellarda9ce8592007-02-05 20:20:30 +0000424
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200425 info->enabled = true;
426
427 /* for compatibility with the original command */
428 info->has_clients = true;
Gerd Hoffmann2d29a432014-12-09 15:27:39 +0100429 info->clients = qmp_query_client_list(vd);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200430
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +0200431 if (vd->lsock == -1) {
Paolo Bonzini417b0b82012-10-10 14:30:58 +0200432 return info;
433 }
434
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +0200435 if (getsockname(vd->lsock, (struct sockaddr *)&sa,
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200436 &salen) == -1) {
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100437 error_setg(errp, QERR_UNDEFINED_ERROR);
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200438 goto out_error;
aliguori1ff7df12009-03-06 20:27:05 +0000439 }
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200440
441 if (getnameinfo((struct sockaddr *)&sa, salen,
442 host, sizeof(host),
443 serv, sizeof(serv),
444 NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100445 error_setg(errp, QERR_UNDEFINED_ERROR);
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200446 goto out_error;
447 }
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;
Wenchao Xiaa5895692014-06-18 08:43:30 +0200456 info->family = inet_netfamily(sa.ss_family);
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200457
458 info->has_auth = true;
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +0200459 info->auth = g_strdup(vnc_auth_name(vd));
bellarda9ce8592007-02-05 20:20:30 +0000460 }
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200461
462 return info;
463
464out_error:
465 qapi_free_VncInfo(info);
466 return NULL;
bellarda9ce8592007-02-05 20:20:30 +0000467}
468
Gerd Hoffmanndf887682014-12-17 15:49:44 +0100469static VncBasicInfoList *qmp_query_server_entry(int socket,
Gerd Hoffmann4478aa72014-12-10 09:49:39 +0100470 bool websocket,
Gerd Hoffmanndf887682014-12-17 15:49:44 +0100471 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);
Gerd Hoffmann4478aa72014-12-10 09:49:39 +0100491 info->websocket = websocket;
Gerd Hoffmanndf887682014-12-17 15:49:44 +0100492
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;
Gerd Hoffmanndf887682014-12-17 15:49:44 +0100522 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 }
Gerd Hoffmanndf887682014-12-17 15:49:44 +0100555 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) {
Gerd Hoffmann4478aa72014-12-10 09:49:39 +0100585 info->server = qmp_query_server_entry(vd->lsock, false,
Gerd Hoffmanndf887682014-12-17 15:49:44 +0100586 info->server);
587 }
Gerd Hoffmanndf887682014-12-17 15:49:44 +0100588 if (vd->lwebsock != -1) {
Gerd Hoffmann4478aa72014-12-10 09:49:39 +0100589 info->server = qmp_query_server_entry(vd->lwebsock, true,
590 info->server);
Gerd Hoffmanndf887682014-12-17 15:49:44 +0100591 }
Gerd Hoffmanndf887682014-12-17 15:49:44 +0100592
593 item = g_new0(VncInfo2List, 1);
594 item->value = info;
595 item->next = prev;
596 prev = item;
597 }
598 return prev;
599}
600
bellard24236862006-04-30 21:28:36 +0000601/* 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
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100608static int vnc_update_client(VncState *vs, int has_dirty, bool sync);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200609static void vnc_disconnect_start(VncState *vs);
bellard24236862006-04-30 21:28:36 +0000610
aliguori753b4052009-02-16 14:59:30 +0000611static void vnc_colordepth(VncState *vs);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100612static void framebuffer_update_request(VncState *vs, int incremental,
613 int x_position, int y_position,
614 int w, int h);
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +0100615static void vnc_refresh(DisplayChangeListener *dcl);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100616static int vnc_refresh_server_surface(VncDisplay *vd);
aliguori7eac3a82008-09-15 16:03:41 +0000617
Peter Lievenbea60dd2014-06-30 10:57:51 +0200618static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
619 VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT),
620 int width, int height,
621 int x, int y, int w, int h) {
Peter Lieven91937222014-01-08 10:08:37 +0100622 /* this is needed this to ensure we updated all affected
623 * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100624 w += (x % VNC_DIRTY_PIXELS_PER_BIT);
625 x -= (x % VNC_DIRTY_PIXELS_PER_BIT);
balrog0486e8a2007-12-11 22:31:32 +0000626
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200627 x = MIN(x, width);
628 y = MIN(y, height);
629 w = MIN(x + w, width) - x;
Peter Lieven91937222014-01-08 10:08:37 +0100630 h = MIN(y + h, height);
balrog788abf82008-05-20 00:07:58 +0000631
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100632 for (; y < h; y++) {
Peter Lievenbea60dd2014-06-30 10:57:51 +0200633 bitmap_set(dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
Peter Lieven91937222014-01-08 10:08:37 +0100634 DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100635 }
bellard24236862006-04-30 21:28:36 +0000636}
637
Peter Lievenbea60dd2014-06-30 10:57:51 +0200638static void vnc_dpy_update(DisplayChangeListener *dcl,
639 int x, int y, int w, int h)
640{
641 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
642 struct VncSurface *s = &vd->guest;
643 int width = pixman_image_get_width(vd->server);
644 int height = pixman_image_get_height(vd->server);
645
646 vnc_set_area_dirty(s->dirty, width, height, x, y, w, h);
647}
648
Corentin Chary70a45682010-05-03 14:31:34 +0200649void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
650 int32_t encoding)
bellard24236862006-04-30 21:28:36 +0000651{
652 vnc_write_u16(vs, x);
653 vnc_write_u16(vs, y);
654 vnc_write_u16(vs, w);
655 vnc_write_u16(vs, h);
656
657 vnc_write_s32(vs, encoding);
658}
659
Tim Hardeck32ed2682013-01-21 11:04:43 +0100660
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200661static void vnc_desktop_resize(VncState *vs)
662{
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200663 if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
664 return;
665 }
Peter Lievenbea60dd2014-06-30 10:57:51 +0200666 if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
667 vs->client_height == pixman_image_get_height(vs->vd->server)) {
Gerd Hoffmann1d4b6382010-05-25 18:25:20 +0200668 return;
669 }
Peter Lievenbea60dd2014-06-30 10:57:51 +0200670 vs->client_width = pixman_image_get_width(vs->vd->server);
671 vs->client_height = pixman_image_get_height(vs->vd->server);
Corentin Charybd023f92010-07-07 20:58:02 +0200672 vnc_lock_output(vs);
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200673 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
674 vnc_write_u8(vs, 0);
675 vnc_write_u16(vs, 1); /* number of rects */
Gerd Hoffmann5862d192010-05-25 18:25:18 +0200676 vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200677 VNC_ENCODING_DESKTOPRESIZE);
Corentin Charybd023f92010-07-07 20:58:02 +0200678 vnc_unlock_output(vs);
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200679 vnc_flush(vs);
680}
681
Corentin Charybd023f92010-07-07 20:58:02 +0200682static void vnc_abort_display_jobs(VncDisplay *vd)
683{
684 VncState *vs;
685
686 QTAILQ_FOREACH(vs, &vd->clients, next) {
687 vnc_lock_output(vs);
688 vs->abort = true;
689 vnc_unlock_output(vs);
690 }
691 QTAILQ_FOREACH(vs, &vd->clients, next) {
692 vnc_jobs_join(vs);
693 }
694 QTAILQ_FOREACH(vs, &vd->clients, next) {
695 vnc_lock_output(vs);
696 vs->abort = false;
697 vnc_unlock_output(vs);
698 }
699}
Corentin Charybd023f92010-07-07 20:58:02 +0200700
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200701int vnc_server_fb_stride(VncDisplay *vd)
702{
703 return pixman_image_get_stride(vd->server);
704}
705
706void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
707{
708 uint8_t *ptr;
709
710 ptr = (uint8_t *)pixman_image_get_data(vd->server);
711 ptr += y * vnc_server_fb_stride(vd);
712 ptr += x * VNC_SERVER_FB_BYTES;
713 return ptr;
714}
715
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +0100716static void vnc_dpy_switch(DisplayChangeListener *dcl,
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +0100717 DisplaySurface *surface)
aliguori753b4052009-02-16 14:59:30 +0000718{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +0100719 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Amit Shah41b4bef2010-02-05 16:34:05 +0530720 VncState *vs;
Peter Lievenbea60dd2014-06-30 10:57:51 +0200721 int width, height;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100722
Corentin Charybd023f92010-07-07 20:58:02 +0200723 vnc_abort_display_jobs(vd);
724
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100725 /* server surface */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200726 qemu_pixman_image_unref(vd->server);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100727 vd->ds = surface;
Peter Lievenbea60dd2014-06-30 10:57:51 +0200728 width = MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
729 VNC_DIRTY_PIXELS_PER_BIT));
730 height = MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200731 vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
Peter Lievenbea60dd2014-06-30 10:57:51 +0200732 width, height, NULL, 0);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100733
734 /* guest surface */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200735#if 0 /* FIXME */
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100736 if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
737 console_color_init(ds);
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200738#endif
739 qemu_pixman_image_unref(vd->guest.fb);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100740 vd->guest.fb = pixman_image_ref(surface->image);
741 vd->guest.format = surface->format;
Peter Lievenbea60dd2014-06-30 10:57:51 +0200742 memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty));
743 vnc_set_area_dirty(vd->guest.dirty, width, height, 0, 0,
744 width, height);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100745
Amit Shah41b4bef2010-02-05 16:34:05 +0530746 QTAILQ_FOREACH(vs, &vd->clients, next) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100747 vnc_colordepth(vs);
Gerd Hoffmann1d4b6382010-05-25 18:25:20 +0200748 vnc_desktop_resize(vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200749 if (vs->vd->cursor) {
750 vnc_cursor_define(vs);
751 }
Peter Lievenbea60dd2014-06-30 10:57:51 +0200752 memset(vs->dirty, 0x00, sizeof(vs->dirty));
753 vnc_set_area_dirty(vs->dirty, width, height, 0, 0,
754 width, height);
aliguori753b4052009-02-16 14:59:30 +0000755 }
756}
757
bellard35127792006-05-14 18:11:49 +0000758/* fastest code */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200759static void vnc_write_pixels_copy(VncState *vs,
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200760 void *pixels, int size)
bellard35127792006-05-14 18:11:49 +0000761{
762 vnc_write(vs, pixels, size);
763}
764
765/* slowest but generic code. */
Corentin Chary70a45682010-05-03 14:31:34 +0200766void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
bellard35127792006-05-14 18:11:49 +0000767{
aliguori7eac3a82008-09-15 16:03:41 +0000768 uint8_t r, g, b;
bellard35127792006-05-14 18:11:49 +0000769
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200770#if VNC_SERVER_FB_FORMAT == PIXMAN_FORMAT(32, PIXMAN_TYPE_ARGB, 0, 8, 8, 8)
771 r = (((v & 0x00ff0000) >> 16) << vs->client_pf.rbits) >> 8;
772 g = (((v & 0x0000ff00) >> 8) << vs->client_pf.gbits) >> 8;
773 b = (((v & 0x000000ff) >> 0) << vs->client_pf.bbits) >> 8;
774#else
775# error need some bits here if you change VNC_SERVER_FB_FORMAT
776#endif
777 v = (r << vs->client_pf.rshift) |
778 (g << vs->client_pf.gshift) |
779 (b << vs->client_pf.bshift);
780 switch (vs->client_pf.bytes_per_pixel) {
bellard35127792006-05-14 18:11:49 +0000781 case 1:
782 buf[0] = v;
783 break;
784 case 2:
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200785 if (vs->client_be) {
bellard35127792006-05-14 18:11:49 +0000786 buf[0] = v >> 8;
787 buf[1] = v;
788 } else {
789 buf[1] = v >> 8;
790 buf[0] = v;
791 }
792 break;
793 default:
794 case 4:
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200795 if (vs->client_be) {
bellard35127792006-05-14 18:11:49 +0000796 buf[0] = v >> 24;
797 buf[1] = v >> 16;
798 buf[2] = v >> 8;
799 buf[3] = v;
800 } else {
801 buf[3] = v >> 24;
802 buf[2] = v >> 16;
803 buf[1] = v >> 8;
804 buf[0] = v;
805 }
806 break;
807 }
808}
809
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200810static void vnc_write_pixels_generic(VncState *vs,
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200811 void *pixels1, int size)
bellard35127792006-05-14 18:11:49 +0000812{
bellard35127792006-05-14 18:11:49 +0000813 uint8_t buf[4];
bellard35127792006-05-14 18:11:49 +0000814
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200815 if (VNC_SERVER_FB_BYTES == 4) {
aliguori7eac3a82008-09-15 16:03:41 +0000816 uint32_t *pixels = pixels1;
817 int n, i;
818 n = size >> 2;
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200819 for (i = 0; i < n; i++) {
aliguori7eac3a82008-09-15 16:03:41 +0000820 vnc_convert_pixel(vs, buf, pixels[i]);
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200821 vnc_write(vs, buf, vs->client_pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000822 }
bellard35127792006-05-14 18:11:49 +0000823 }
824}
825
Corentin Charya8852112010-05-19 09:24:09 +0200826int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000827{
828 int i;
ths60fe76f2007-12-16 03:02:09 +0000829 uint8_t *row;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100830 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000831
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200832 row = vnc_server_fb_ptr(vd, x, y);
bellard24236862006-04-30 21:28:36 +0000833 for (i = 0; i < h; i++) {
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200834 vs->write_pixels(vs, row, w * VNC_SERVER_FB_BYTES);
835 row += vnc_server_fb_stride(vd);
bellard24236862006-04-30 21:28:36 +0000836 }
Corentin Charya8852112010-05-19 09:24:09 +0200837 return 1;
bellard24236862006-04-30 21:28:36 +0000838}
839
Corentin Charybd023f92010-07-07 20:58:02 +0200840int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000841{
Corentin Charya8852112010-05-19 09:24:09 +0200842 int n = 0;
Peter Lievende3f7de2015-08-27 14:46:25 +0200843 bool encode_raw = false;
844 size_t saved_offs = vs->output.offset;
Corentin Charya8852112010-05-19 09:24:09 +0200845
aliguorifb437312009-02-02 15:58:43 +0000846 switch(vs->vnc_encoding) {
aliguori28a76be2009-03-06 20:27:40 +0000847 case VNC_ENCODING_ZLIB:
Corentin Charya8852112010-05-19 09:24:09 +0200848 n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
aliguori28a76be2009-03-06 20:27:40 +0000849 break;
850 case VNC_ENCODING_HEXTILE:
851 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
Corentin Charya8852112010-05-19 09:24:09 +0200852 n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
aliguori28a76be2009-03-06 20:27:40 +0000853 break;
Corentin Chary380282b2010-05-19 09:24:10 +0200854 case VNC_ENCODING_TIGHT:
855 n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
856 break;
Corentin Charyefe556a2010-07-07 20:57:56 +0200857 case VNC_ENCODING_TIGHT_PNG:
858 n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
859 break;
Corentin Chary148954f2011-02-04 09:06:01 +0100860 case VNC_ENCODING_ZRLE:
861 n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
862 break;
863 case VNC_ENCODING_ZYWRLE:
864 n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
865 break;
aliguori28a76be2009-03-06 20:27:40 +0000866 default:
Peter Lievende3f7de2015-08-27 14:46:25 +0200867 encode_raw = true;
aliguori28a76be2009-03-06 20:27:40 +0000868 break;
aliguorifb437312009-02-02 15:58:43 +0000869 }
Peter Lievende3f7de2015-08-27 14:46:25 +0200870
871 /* If the client has the same pixel format as our internal buffer and
872 * a RAW encoding would need less space fall back to RAW encoding to
873 * save bandwidth and processing power in the client. */
874 if (!encode_raw && vs->write_pixels == vnc_write_pixels_copy &&
875 12 + h * w * VNC_SERVER_FB_BYTES <= (vs->output.offset - saved_offs)) {
876 vs->output.offset = saved_offs;
877 encode_raw = true;
878 }
879
880 if (encode_raw) {
881 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
882 n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
883 }
884
Corentin Charya8852112010-05-19 09:24:09 +0200885 return n;
bellard24236862006-04-30 21:28:36 +0000886}
887
aliguori753b4052009-02-16 14:59:30 +0000888static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000889{
Gerd Hoffmann3e28c9a2009-07-27 17:10:48 +0200890 /* send bitblit op to the vnc client */
Corentin Charybd023f92010-07-07 20:58:02 +0200891 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +0100892 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
bellard24236862006-04-30 21:28:36 +0000893 vnc_write_u8(vs, 0);
894 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000895 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
bellard24236862006-04-30 21:28:36 +0000896 vnc_write_u16(vs, src_x);
897 vnc_write_u16(vs, src_y);
Corentin Charybd023f92010-07-07 20:58:02 +0200898 vnc_unlock_output(vs);
bellard24236862006-04-30 21:28:36 +0000899 vnc_flush(vs);
900}
901
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100902static void vnc_dpy_copy(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100903 int src_x, int src_y,
904 int dst_x, int dst_y, int w, int h)
aliguori753b4052009-02-16 14:59:30 +0000905{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +0100906 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200907 VncState *vs, *vn;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100908 uint8_t *src_row;
909 uint8_t *dst_row;
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200910 int i, x, y, pitch, inc, w_lim, s;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100911 int cmp_bytes;
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200912
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100913 vnc_refresh_server_surface(vd);
Amit Shah41b4bef2010-02-05 16:34:05 +0530914 QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200915 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
916 vs->force_update = 1;
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100917 vnc_update_client(vs, 1, true);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200918 /* vs might be free()ed here */
919 }
920 }
921
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100922 /* do bitblit op on the local surface too */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200923 pitch = vnc_server_fb_stride(vd);
924 src_row = vnc_server_fb_ptr(vd, src_x, src_y);
925 dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100926 y = dst_y;
927 inc = 1;
928 if (dst_y > src_y) {
929 /* copy backwards */
930 src_row += pitch * (h-1);
931 dst_row += pitch * (h-1);
932 pitch = -pitch;
933 y = dst_y + h - 1;
934 inc = -1;
935 }
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100936 w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
937 if (w_lim < 0) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100938 w_lim = w;
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100939 } else {
940 w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT);
941 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100942 for (i = 0; i < h; i++) {
943 for (x = 0; x <= w_lim;
944 x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
945 if (x == w_lim) {
946 if ((s = w - w_lim) == 0)
947 break;
948 } else if (!x) {
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100949 s = (VNC_DIRTY_PIXELS_PER_BIT -
950 (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100951 s = MIN(s, w_lim);
952 } else {
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100953 s = VNC_DIRTY_PIXELS_PER_BIT;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100954 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200955 cmp_bytes = s * VNC_SERVER_FB_BYTES;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100956 if (memcmp(src_row, dst_row, cmp_bytes) == 0)
957 continue;
958 memmove(dst_row, src_row, cmp_bytes);
Amit Shah41b4bef2010-02-05 16:34:05 +0530959 QTAILQ_FOREACH(vs, &vd->clients, next) {
960 if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100961 set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT),
962 vs->dirty[y]);
Amit Shah41b4bef2010-02-05 16:34:05 +0530963 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100964 }
965 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200966 src_row += pitch - w * VNC_SERVER_FB_BYTES;
967 dst_row += pitch - w * VNC_SERVER_FB_BYTES;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100968 y += inc;
969 }
970
Amit Shah41b4bef2010-02-05 16:34:05 +0530971 QTAILQ_FOREACH(vs, &vd->clients, next) {
972 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
aliguori753b4052009-02-16 14:59:30 +0000973 vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
Amit Shah41b4bef2010-02-05 16:34:05 +0530974 }
aliguori753b4052009-02-16 14:59:30 +0000975 }
976}
977
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100978static void vnc_mouse_set(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100979 int x, int y, int visible)
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200980{
981 /* can we ask the client(s) to move the pointer ??? */
982}
983
984static int vnc_cursor_define(VncState *vs)
985{
986 QEMUCursor *c = vs->vd->cursor;
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200987 int isize;
988
989 if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
Corentin Charyd01f9592010-07-07 20:58:03 +0200990 vnc_lock_output(vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200991 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
992 vnc_write_u8(vs, 0); /* padding */
993 vnc_write_u16(vs, 1); /* # of rects */
994 vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
995 VNC_ENCODING_RICH_CURSOR);
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200996 isize = c->width * c->height * vs->client_pf.bytes_per_pixel;
997 vnc_write_pixels_generic(vs, c->data, isize);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200998 vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
Corentin Charyd01f9592010-07-07 20:58:03 +0200999 vnc_unlock_output(vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +02001000 return 0;
1001 }
1002 return -1;
1003}
1004
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001005static void vnc_dpy_cursor_define(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001006 QEMUCursor *c)
Gerd Hoffmannd467b672010-05-21 11:54:34 +02001007{
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +02001008 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Gerd Hoffmannd467b672010-05-21 11:54:34 +02001009 VncState *vs;
1010
1011 cursor_put(vd->cursor);
Anthony Liguori7267c092011-08-20 22:09:37 -05001012 g_free(vd->cursor_mask);
Gerd Hoffmannd467b672010-05-21 11:54:34 +02001013
1014 vd->cursor = c;
1015 cursor_get(vd->cursor);
1016 vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
Anthony Liguori7267c092011-08-20 22:09:37 -05001017 vd->cursor_mask = g_malloc0(vd->cursor_msize);
Gerd Hoffmannd467b672010-05-21 11:54:34 +02001018 cursor_get_mono_mask(c, 0, vd->cursor_mask);
1019
1020 QTAILQ_FOREACH(vs, &vd->clients, next) {
1021 vnc_cursor_define(vs);
1022 }
1023}
1024
Chih-Min Chao4769a882015-04-09 02:04:12 +08001025static int find_and_clear_dirty_height(VncState *vs,
Corentin Chary6c71a532011-02-04 09:06:06 +01001026 int y, int last_x, int x, int height)
bellard24236862006-04-30 21:28:36 +00001027{
1028 int h;
1029
Corentin Chary6c71a532011-02-04 09:06:06 +01001030 for (h = 1; h < (height - y); h++) {
Corentin Charybc2429b2011-02-04 09:06:05 +01001031 if (!test_bit(last_x, vs->dirty[y + h])) {
aliguori28a76be2009-03-06 20:27:40 +00001032 break;
Corentin Charybc2429b2011-02-04 09:06:05 +01001033 }
Peter Lieven863d7c92014-01-08 10:08:36 +01001034 bitmap_clear(vs->dirty[y + h], last_x, x - last_x);
bellard24236862006-04-30 21:28:36 +00001035 }
1036
1037 return h;
1038}
1039
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +01001040static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
bellard24236862006-04-30 21:28:36 +00001041{
Gerd Hoffmann63658282014-07-23 11:52:02 +02001042 vs->has_dirty += has_dirty;
bellard24236862006-04-30 21:28:36 +00001043 if (vs->need_update && vs->csock != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +01001044 VncDisplay *vd = vs->vd;
Corentin Charybd023f92010-07-07 20:58:02 +02001045 VncJob *job;
aliguori28a76be2009-03-06 20:27:40 +00001046 int y;
Peter Lieven2f487a3d2014-03-17 18:38:58 +01001047 int height, width;
Corentin Charybd023f92010-07-07 20:58:02 +02001048 int n = 0;
1049
Stefano Stabellini703bc682009-08-03 10:54:05 +01001050 if (vs->output.offset && !vs->audio_cap && !vs->force_update)
aliguoric522d0e2009-03-20 15:59:24 +00001051 /* kernel send buffers are full -> drop frames to throttle */
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01001052 return 0;
balroga0ecfb72008-01-13 23:51:53 +00001053
Gerd Hoffmann63658282014-07-23 11:52:02 +02001054 if (!vs->has_dirty && !vs->audio_cap && !vs->force_update)
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01001055 return 0;
bellard24236862006-04-30 21:28:36 +00001056
aliguori6baebed2009-03-20 15:59:14 +00001057 /*
1058 * Send screen updates to the vnc client using the server
1059 * surface and server dirty map. guest surface updates
1060 * happening in parallel don't disturb us, the next pass will
1061 * send them to the client.
1062 */
Corentin Charybd023f92010-07-07 20:58:02 +02001063 job = vnc_job_new(vs);
bellard24236862006-04-30 21:28:36 +00001064
Peter Lievenbea60dd2014-06-30 10:57:51 +02001065 height = pixman_image_get_height(vd->server);
1066 width = pixman_image_get_width(vd->server);
Gerd Hoffmann847ce6a2010-05-25 18:25:19 +02001067
Peter Lieven12b316d2014-01-08 10:08:35 +01001068 y = 0;
1069 for (;;) {
1070 int x, h;
1071 unsigned long x2;
1072 unsigned long offset = find_next_bit((unsigned long *) &vs->dirty,
1073 height * VNC_DIRTY_BPL(vs),
1074 y * VNC_DIRTY_BPL(vs));
1075 if (offset == height * VNC_DIRTY_BPL(vs)) {
1076 /* no more dirty bits */
1077 break;
aliguori28a76be2009-03-06 20:27:40 +00001078 }
Peter Lieven12b316d2014-01-08 10:08:35 +01001079 y = offset / VNC_DIRTY_BPL(vs);
1080 x = offset % VNC_DIRTY_BPL(vs);
1081 x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y],
1082 VNC_DIRTY_BPL(vs), x);
1083 bitmap_clear(vs->dirty[y], x, x2 - x);
1084 h = find_and_clear_dirty_height(vs, y, x, x2, height);
Peter Lieven2f487a3d2014-03-17 18:38:58 +01001085 x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT);
1086 if (x2 > x) {
1087 n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y,
1088 (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h);
1089 }
Peter Lieven0e7d6f62015-02-02 16:25:34 +01001090 if (!x && x2 == width / VNC_DIRTY_PIXELS_PER_BIT) {
1091 y += h;
1092 if (y == height) {
1093 break;
1094 }
1095 }
aliguori28a76be2009-03-06 20:27:40 +00001096 }
Corentin Charybd023f92010-07-07 20:58:02 +02001097
1098 vnc_job_push(job);
Gerd Hoffmanneb214ff2014-06-13 10:23:10 +02001099 if (sync) {
1100 vnc_jobs_join(vs);
1101 }
aliguoric522d0e2009-03-20 15:59:24 +00001102 vs->force_update = 0;
Gerd Hoffmann63658282014-07-23 11:52:02 +02001103 vs->has_dirty = 0;
Corentin Charybd023f92010-07-07 20:58:02 +02001104 return n;
bellard24236862006-04-30 21:28:36 +00001105 }
bellard24236862006-04-30 21:28:36 +00001106
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +01001107 if (vs->csock == -1) {
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001108 vnc_disconnect_finish(vs);
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +01001109 } else if (sync) {
1110 vnc_jobs_join(vs);
1111 }
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01001112
1113 return 0;
bellard24236862006-04-30 21:28:36 +00001114}
1115
malc429a8ed2008-12-01 20:57:48 +00001116/* audio */
1117static void audio_capture_notify(void *opaque, audcnotification_e cmd)
1118{
1119 VncState *vs = opaque;
1120
1121 switch (cmd) {
1122 case AUD_CNOTIFY_DISABLE:
Corentin Charybd023f92010-07-07 20:58:02 +02001123 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001124 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
1125 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
1126 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
Corentin Charybd023f92010-07-07 20:58:02 +02001127 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +00001128 vnc_flush(vs);
1129 break;
1130
1131 case AUD_CNOTIFY_ENABLE:
Corentin Charybd023f92010-07-07 20:58:02 +02001132 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001133 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
1134 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
1135 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
Corentin Charybd023f92010-07-07 20:58:02 +02001136 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +00001137 vnc_flush(vs);
1138 break;
1139 }
1140}
1141
1142static void audio_capture_destroy(void *opaque)
1143{
1144}
1145
1146static void audio_capture(void *opaque, void *buf, int size)
1147{
1148 VncState *vs = opaque;
1149
Corentin Charybd023f92010-07-07 20:58:02 +02001150 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001151 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
1152 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
1153 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
malc429a8ed2008-12-01 20:57:48 +00001154 vnc_write_u32(vs, size);
1155 vnc_write(vs, buf, size);
Corentin Charybd023f92010-07-07 20:58:02 +02001156 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +00001157 vnc_flush(vs);
1158}
1159
1160static void audio_add(VncState *vs)
1161{
1162 struct audio_capture_ops ops;
1163
1164 if (vs->audio_cap) {
Cole Robinson027a79c2014-03-21 19:42:21 -04001165 error_report("audio already running");
malc429a8ed2008-12-01 20:57:48 +00001166 return;
1167 }
1168
1169 ops.notify = audio_capture_notify;
1170 ops.destroy = audio_capture_destroy;
1171 ops.capture = audio_capture;
1172
malc1a7dafc2009-05-14 03:11:35 +04001173 vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
malc429a8ed2008-12-01 20:57:48 +00001174 if (!vs->audio_cap) {
Cole Robinson027a79c2014-03-21 19:42:21 -04001175 error_report("Failed to add audio capture");
malc429a8ed2008-12-01 20:57:48 +00001176 }
1177}
1178
1179static void audio_del(VncState *vs)
1180{
1181 if (vs->audio_cap) {
1182 AUD_del_capture(vs->audio_cap, vs);
1183 vs->audio_cap = NULL;
1184 }
1185}
1186
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001187static void vnc_disconnect_start(VncState *vs)
1188{
1189 if (vs->csock == -1)
1190 return;
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01001191 vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
Fam Zheng82e1cc42015-06-04 14:45:18 +08001192 qemu_set_fd_handler(vs->csock, NULL, NULL, NULL);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001193 closesocket(vs->csock);
1194 vs->csock = -1;
1195}
1196
Tim Hardeck7536ee42013-01-21 11:04:44 +01001197void vnc_disconnect_finish(VncState *vs)
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001198{
Corentin Chary7d964c92011-02-04 09:05:56 +01001199 int i;
1200
Corentin Charybd023f92010-07-07 20:58:02 +02001201 vnc_jobs_join(vs); /* Wait encoding jobs */
1202
1203 vnc_lock_output(vs);
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +02001204 vnc_qmp_event(vs, QAPI_EVENT_VNC_DISCONNECTED);
Luiz Capitulino0d72f3d2010-01-14 14:50:58 -02001205
Corentin Chary5d418e32010-05-19 09:24:07 +02001206 buffer_free(&vs->input);
1207 buffer_free(&vs->output);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001208 buffer_free(&vs->ws_input);
1209 buffer_free(&vs->ws_output);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02001210
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +02001211 qapi_free_VncClientInfo(vs->info);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02001212
Corentin Chary161c4f22010-05-19 09:24:08 +02001213 vnc_zlib_clear(vs);
Corentin Chary380282b2010-05-19 09:24:10 +02001214 vnc_tight_clear(vs);
Corentin Chary148954f2011-02-04 09:06:01 +01001215 vnc_zrle_clear(vs);
Corentin Chary161c4f22010-05-19 09:24:08 +02001216
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001217 qcrypto_tls_session_free(vs->tls);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001218#ifdef CONFIG_VNC_SASL
1219 vnc_sasl_client_cleanup(vs);
1220#endif /* CONFIG_VNC_SASL */
1221 audio_del(vs);
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001222 vnc_release_modifiers(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001223
Tim Hardeck6fd8e792013-01-21 11:04:45 +01001224 if (vs->initialized) {
1225 QTAILQ_REMOVE(&vs->vd->clients, vs, next);
1226 qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
1227 }
Amit Shah41b4bef2010-02-05 16:34:05 +05301228
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01001229 if (vs->vd->lock_key_sync)
1230 qemu_remove_led_event_handler(vs->led);
Corentin Charybd023f92010-07-07 20:58:02 +02001231 vnc_unlock_output(vs);
1232
Corentin Charybd023f92010-07-07 20:58:02 +02001233 qemu_mutex_destroy(&vs->output_mutex);
Tim Hardeck6fd8e792013-01-21 11:04:45 +01001234 if (vs->bh != NULL) {
1235 qemu_bh_delete(vs->bh);
1236 }
Corentin Chary175b2a62012-03-14 07:58:47 +01001237 buffer_free(&vs->jobs_buffer);
Corentin Chary175b2a62012-03-14 07:58:47 +01001238
Corentin Chary7d964c92011-02-04 09:05:56 +01001239 for (i = 0; i < VNC_STAT_ROWS; ++i) {
Anthony Liguori7267c092011-08-20 22:09:37 -05001240 g_free(vs->lossy_rect[i]);
Corentin Chary7d964c92011-02-04 09:05:56 +01001241 }
Anthony Liguori7267c092011-08-20 22:09:37 -05001242 g_free(vs->lossy_rect);
1243 g_free(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001244}
aliguori2f9606b2009-03-06 20:27:28 +00001245
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001246ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, int last_errno)
bellard24236862006-04-30 21:28:36 +00001247{
1248 if (ret == 0 || ret == -1) {
balrogea01e5f2008-04-24 23:40:55 +00001249 if (ret == -1) {
1250 switch (last_errno) {
1251 case EINTR:
1252 case EAGAIN:
1253#ifdef _WIN32
1254 case WSAEWOULDBLOCK:
1255#endif
1256 return 0;
1257 default:
1258 break;
1259 }
1260 }
bellard24236862006-04-30 21:28:36 +00001261
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001262 VNC_DEBUG("Closing down client sock: ret %zd, errno %d\n",
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001263 ret, ret < 0 ? last_errno : 0);
1264 vnc_disconnect_start(vs);
aliguori6baebed2009-03-20 15:59:14 +00001265
aliguori28a76be2009-03-06 20:27:40 +00001266 return 0;
bellard24236862006-04-30 21:28:36 +00001267 }
1268 return ret;
1269}
1270
aliguori5fb6c7a2009-03-06 20:27:23 +00001271
1272void vnc_client_error(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001273{
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001274 VNC_DEBUG("Closing down client sock: protocol error\n");
1275 vnc_disconnect_start(vs);
bellard24236862006-04-30 21:28:36 +00001276}
1277
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001278
1279ssize_t vnc_tls_pull(char *buf, size_t len, void *opaque)
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001280{
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001281 VncState *vs = opaque;
1282 ssize_t ret;
1283
1284 retry:
1285 ret = qemu_recv(vs->csock, buf, len, 0);
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001286 if (ret < 0) {
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001287 if (errno == EINTR) {
1288 goto retry;
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001289 }
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001290 return -1;
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001291 }
1292 return ret;
1293}
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001294
1295
1296ssize_t vnc_tls_push(const char *buf, size_t len, void *opaque)
1297{
1298 VncState *vs = opaque;
1299 ssize_t ret;
1300
1301 retry:
1302 ret = send(vs->csock, buf, len, 0);
1303 if (ret < 0) {
1304 if (errno == EINTR) {
1305 goto retry;
1306 }
1307 return -1;
1308 }
1309 return ret;
1310}
1311
aliguori2f9606b2009-03-06 20:27:28 +00001312
1313/*
1314 * Called to write a chunk of data to the client socket. The data may
1315 * be the raw data, or may have already been encoded by SASL.
1316 * The data will be written either straight onto the socket, or
1317 * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1318 *
1319 * NB, it is theoretically possible to have 2 layers of encryption,
1320 * both SASL, and this TLS layer. It is highly unlikely in practice
1321 * though, since SASL encryption will typically be a no-op if TLS
1322 * is active
1323 *
1324 * Returns the number of bytes written, which may be less than
1325 * the requested 'datalen' if the socket would block. Returns
1326 * -1 on error, and disconnects the client socket.
1327 */
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001328ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001329{
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001330 ssize_t ret;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001331 int err = 0;
1332 if (vs->tls) {
1333 ret = qcrypto_tls_session_write(vs->tls, (const char *)data, datalen);
1334 if (ret < 0) {
1335 err = errno;
1336 }
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001337 } else {
Daniel P. Berrange7b45a002015-03-17 13:42:59 +00001338 ret = send(vs->csock, (const void *)data, datalen, 0);
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001339 if (ret < 0) {
1340 err = socket_error();
1341 }
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001342 }
aliguori23decc82009-03-20 15:59:18 +00001343 VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001344 return vnc_client_io_error(vs, ret, err);
aliguori2f9606b2009-03-06 20:27:28 +00001345}
1346
1347
1348/*
1349 * Called to write buffered data to the client socket, when not
1350 * using any SASL SSF encryption layers. Will write as much data
1351 * as possible without blocking. If all buffered data is written,
1352 * will switch the FD poll() handler back to read monitoring.
1353 *
1354 * Returns the number of bytes written, which may be less than
1355 * the buffered output data if the socket would block. Returns
1356 * -1 on error, and disconnects the client socket.
1357 */
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001358static ssize_t vnc_client_write_plain(VncState *vs)
aliguori2f9606b2009-03-06 20:27:28 +00001359{
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001360 ssize_t ret;
aliguori2f9606b2009-03-06 20:27:28 +00001361
1362#ifdef CONFIG_VNC_SASL
aliguori23decc82009-03-20 15:59:18 +00001363 VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
aliguori2f9606b2009-03-06 20:27:28 +00001364 vs->output.buffer, vs->output.capacity, vs->output.offset,
1365 vs->sasl.waitWriteSSF);
1366
1367 if (vs->sasl.conn &&
1368 vs->sasl.runSSF &&
1369 vs->sasl.waitWriteSSF) {
1370 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
1371 if (ret)
1372 vs->sasl.waitWriteSSF -= ret;
1373 } else
1374#endif /* CONFIG_VNC_SASL */
1375 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
bellard24236862006-04-30 21:28:36 +00001376 if (!ret)
aliguori2f9606b2009-03-06 20:27:28 +00001377 return 0;
bellard24236862006-04-30 21:28:36 +00001378
Tim Hardeck32ed2682013-01-21 11:04:43 +01001379 buffer_advance(&vs->output, ret);
bellard24236862006-04-30 21:28:36 +00001380
1381 if (vs->output.offset == 0) {
Fam Zheng82e1cc42015-06-04 14:45:18 +08001382 qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00001383 }
aliguori2f9606b2009-03-06 20:27:28 +00001384
1385 return ret;
1386}
1387
1388
1389/*
1390 * First function called whenever there is data to be written to
1391 * the client socket. Will delegate actual work according to whether
1392 * SASL SSF layers are enabled (thus requiring encryption calls)
1393 */
Corentin Charybd023f92010-07-07 20:58:02 +02001394static void vnc_client_write_locked(void *opaque)
aliguori2f9606b2009-03-06 20:27:28 +00001395{
aliguori2f9606b2009-03-06 20:27:28 +00001396 VncState *vs = opaque;
1397
1398#ifdef CONFIG_VNC_SASL
1399 if (vs->sasl.conn &&
1400 vs->sasl.runSSF &&
Blue Swirl9678d952010-04-25 18:35:52 +00001401 !vs->sasl.waitWriteSSF) {
1402 vnc_client_write_sasl(vs);
1403 } else
aliguori2f9606b2009-03-06 20:27:28 +00001404#endif /* CONFIG_VNC_SASL */
Tim Hardeck7536ee42013-01-21 11:04:44 +01001405 {
Tim Hardeck7536ee42013-01-21 11:04:44 +01001406 if (vs->encode_ws) {
1407 vnc_client_write_ws(vs);
Daniel P. Berrange8e9b0d22015-07-01 18:10:36 +01001408 } else {
Tim Hardeck7536ee42013-01-21 11:04:44 +01001409 vnc_client_write_plain(vs);
1410 }
1411 }
bellard24236862006-04-30 21:28:36 +00001412}
1413
Corentin Charybd023f92010-07-07 20:58:02 +02001414void vnc_client_write(void *opaque)
1415{
1416 VncState *vs = opaque;
1417
1418 vnc_lock_output(vs);
Daniel P. Berrange8e9b0d22015-07-01 18:10:36 +01001419 if (vs->output.offset || vs->ws_output.offset) {
Corentin Charybd023f92010-07-07 20:58:02 +02001420 vnc_client_write_locked(opaque);
Yoshiaki Tamuraac711032010-08-20 19:10:41 +09001421 } else if (vs->csock != -1) {
Fam Zheng82e1cc42015-06-04 14:45:18 +08001422 qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs);
Corentin Charybd023f92010-07-07 20:58:02 +02001423 }
1424 vnc_unlock_output(vs);
1425}
1426
aliguori5fb6c7a2009-03-06 20:27:23 +00001427void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
bellard24236862006-04-30 21:28:36 +00001428{
1429 vs->read_handler = func;
1430 vs->read_handler_expect = expecting;
1431}
1432
aliguori2f9606b2009-03-06 20:27:28 +00001433
1434/*
1435 * Called to read a chunk of data from the client socket. The data may
1436 * be the raw data, or may need to be further decoded by SASL.
1437 * The data will be read either straight from to the socket, or
1438 * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1439 *
1440 * NB, it is theoretically possible to have 2 layers of encryption,
1441 * both SASL, and this TLS layer. It is highly unlikely in practice
1442 * though, since SASL encryption will typically be a no-op if TLS
1443 * is active
1444 *
1445 * Returns the number of bytes read, which may be less than
1446 * the requested 'datalen' if the socket would block. Returns
1447 * -1 on error, and disconnects the client socket.
1448 */
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001449ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001450{
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001451 ssize_t ret;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001452 int err = -1;
1453 if (vs->tls) {
1454 ret = qcrypto_tls_session_read(vs->tls, (char *)data, datalen);
1455 if (ret < 0) {
1456 err = errno;
1457 }
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001458 } else {
Daniel P. Berrange7b45a002015-03-17 13:42:59 +00001459 ret = qemu_recv(vs->csock, data, datalen, 0);
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001460 if (ret < 0) {
1461 err = socket_error();
1462 }
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001463 }
aliguori23decc82009-03-20 15:59:18 +00001464 VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01001465 return vnc_client_io_error(vs, ret, err);
aliguori2f9606b2009-03-06 20:27:28 +00001466}
1467
1468
1469/*
1470 * Called to read data from the client socket to the input buffer,
1471 * when not using any SASL SSF encryption layers. Will read as much
1472 * data as possible without blocking.
1473 *
1474 * Returns the number of bytes read. Returns -1 on error, and
1475 * disconnects the client socket.
1476 */
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001477static ssize_t vnc_client_read_plain(VncState *vs)
aliguori2f9606b2009-03-06 20:27:28 +00001478{
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001479 ssize_t ret;
aliguori23decc82009-03-20 15:59:18 +00001480 VNC_DEBUG("Read plain %p size %zd offset %zd\n",
aliguori2f9606b2009-03-06 20:27:28 +00001481 vs->input.buffer, vs->input.capacity, vs->input.offset);
1482 buffer_reserve(&vs->input, 4096);
1483 ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
1484 if (!ret)
1485 return 0;
1486 vs->input.offset += ret;
1487 return ret;
1488}
1489
Corentin Chary175b2a62012-03-14 07:58:47 +01001490static void vnc_jobs_bh(void *opaque)
1491{
1492 VncState *vs = opaque;
1493
1494 vnc_jobs_consume_buffer(vs);
1495}
aliguori2f9606b2009-03-06 20:27:28 +00001496
1497/*
1498 * First function called whenever there is more data to be read from
1499 * the client socket. Will delegate actual work according to whether
1500 * SASL SSF layers are enabled (thus requiring decryption calls)
1501 */
1502void vnc_client_read(void *opaque)
1503{
1504 VncState *vs = opaque;
Daniel P. Berrangefdd1ab62015-08-06 15:35:55 +01001505 ssize_t ret;
aliguori2f9606b2009-03-06 20:27:28 +00001506
1507#ifdef CONFIG_VNC_SASL
1508 if (vs->sasl.conn && vs->sasl.runSSF)
1509 ret = vnc_client_read_sasl(vs);
1510 else
1511#endif /* CONFIG_VNC_SASL */
Tim Hardeck7536ee42013-01-21 11:04:44 +01001512 if (vs->encode_ws) {
1513 ret = vnc_client_read_ws(vs);
1514 if (ret == -1) {
1515 vnc_disconnect_start(vs);
1516 return;
1517 } else if (ret == -2) {
1518 vnc_client_error(vs);
1519 return;
1520 }
Daniel P. Berrange8e9b0d22015-07-01 18:10:36 +01001521 } else {
1522 ret = vnc_client_read_plain(vs);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001523 }
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001524 if (!ret) {
1525 if (vs->csock == -1)
1526 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001527 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001528 }
bellard24236862006-04-30 21:28:36 +00001529
bellard24236862006-04-30 21:28:36 +00001530 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
aliguori28a76be2009-03-06 20:27:40 +00001531 size_t len = vs->read_handler_expect;
1532 int ret;
bellard24236862006-04-30 21:28:36 +00001533
aliguori28a76be2009-03-06 20:27:40 +00001534 ret = vs->read_handler(vs, vs->input.buffer, len);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001535 if (vs->csock == -1) {
1536 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001537 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001538 }
bellard24236862006-04-30 21:28:36 +00001539
aliguori28a76be2009-03-06 20:27:40 +00001540 if (!ret) {
Tim Hardeck32ed2682013-01-21 11:04:43 +01001541 buffer_advance(&vs->input, len);
aliguori28a76be2009-03-06 20:27:40 +00001542 } else {
1543 vs->read_handler_expect = ret;
1544 }
bellard24236862006-04-30 21:28:36 +00001545 }
1546}
1547
aliguori5fb6c7a2009-03-06 20:27:23 +00001548void vnc_write(VncState *vs, const void *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001549{
1550 buffer_reserve(&vs->output, len);
1551
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001552 if (vs->csock != -1 && buffer_empty(&vs->output)) {
Fam Zheng82e1cc42015-06-04 14:45:18 +08001553 qemu_set_fd_handler(vs->csock, vnc_client_read, vnc_client_write, vs);
bellard24236862006-04-30 21:28:36 +00001554 }
1555
1556 buffer_append(&vs->output, data, len);
1557}
1558
aliguori5fb6c7a2009-03-06 20:27:23 +00001559void vnc_write_s32(VncState *vs, int32_t value)
bellard24236862006-04-30 21:28:36 +00001560{
1561 vnc_write_u32(vs, *(uint32_t *)&value);
1562}
1563
aliguori5fb6c7a2009-03-06 20:27:23 +00001564void vnc_write_u32(VncState *vs, uint32_t value)
bellard24236862006-04-30 21:28:36 +00001565{
1566 uint8_t buf[4];
1567
1568 buf[0] = (value >> 24) & 0xFF;
1569 buf[1] = (value >> 16) & 0xFF;
1570 buf[2] = (value >> 8) & 0xFF;
1571 buf[3] = value & 0xFF;
1572
1573 vnc_write(vs, buf, 4);
1574}
1575
aliguori5fb6c7a2009-03-06 20:27:23 +00001576void vnc_write_u16(VncState *vs, uint16_t value)
bellard24236862006-04-30 21:28:36 +00001577{
bellard64f5a132006-08-24 20:36:44 +00001578 uint8_t buf[2];
bellard24236862006-04-30 21:28:36 +00001579
1580 buf[0] = (value >> 8) & 0xFF;
1581 buf[1] = value & 0xFF;
1582
1583 vnc_write(vs, buf, 2);
1584}
1585
aliguori5fb6c7a2009-03-06 20:27:23 +00001586void vnc_write_u8(VncState *vs, uint8_t value)
bellard24236862006-04-30 21:28:36 +00001587{
1588 vnc_write(vs, (char *)&value, 1);
1589}
1590
aliguori5fb6c7a2009-03-06 20:27:23 +00001591void vnc_flush(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001592{
Corentin Charybd023f92010-07-07 20:58:02 +02001593 vnc_lock_output(vs);
Daniel P. Berrange8e9b0d22015-07-01 18:10:36 +01001594 if (vs->csock != -1 && (vs->output.offset ||
1595 vs->ws_output.offset)) {
Corentin Charybd023f92010-07-07 20:58:02 +02001596 vnc_client_write_locked(vs);
1597 }
1598 vnc_unlock_output(vs);
bellard24236862006-04-30 21:28:36 +00001599}
1600
Blue Swirl71a8cde2012-10-28 11:04:48 +00001601static uint8_t read_u8(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001602{
1603 return data[offset];
1604}
1605
Blue Swirl71a8cde2012-10-28 11:04:48 +00001606static uint16_t read_u16(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001607{
1608 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
1609}
1610
Blue Swirl71a8cde2012-10-28 11:04:48 +00001611static int32_t read_s32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001612{
1613 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001614 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001615}
1616
aliguori5fb6c7a2009-03-06 20:27:23 +00001617uint32_t read_u32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001618{
1619 return ((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001620 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001621}
1622
ths60fe76f2007-12-16 03:02:09 +00001623static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
bellard24236862006-04-30 21:28:36 +00001624{
1625}
1626
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001627static void check_pointer_type_change(Notifier *notifier, void *data)
bellard564c3372007-02-05 20:14:10 +00001628{
Anthony Liguori37c34d92010-03-10 09:38:29 -06001629 VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001630 int absolute = qemu_input_is_absolute();
Anthony Liguori37c34d92010-03-10 09:38:29 -06001631
aliguori29fa4ed2009-02-02 15:58:29 +00001632 if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
Corentin Charybd023f92010-07-07 20:58:02 +02001633 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001634 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
aliguori28a76be2009-03-06 20:27:40 +00001635 vnc_write_u8(vs, 0);
1636 vnc_write_u16(vs, 1);
1637 vnc_framebuffer_update(vs, absolute, 0,
Peter Lievenbea60dd2014-06-30 10:57:51 +02001638 pixman_image_get_width(vs->vd->server),
1639 pixman_image_get_height(vs->vd->server),
aliguori29fa4ed2009-02-02 15:58:29 +00001640 VNC_ENCODING_POINTER_TYPE_CHANGE);
Corentin Charybd023f92010-07-07 20:58:02 +02001641 vnc_unlock_output(vs);
aliguori28a76be2009-03-06 20:27:40 +00001642 vnc_flush(vs);
bellard564c3372007-02-05 20:14:10 +00001643 }
1644 vs->absolute = absolute;
1645}
1646
bellard24236862006-04-30 21:28:36 +00001647static void pointer_event(VncState *vs, int button_mask, int x, int y)
1648{
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001649 static uint32_t bmap[INPUT_BUTTON_MAX] = {
1650 [INPUT_BUTTON_LEFT] = 0x01,
1651 [INPUT_BUTTON_MIDDLE] = 0x02,
1652 [INPUT_BUTTON_RIGHT] = 0x04,
1653 [INPUT_BUTTON_WHEEL_UP] = 0x08,
1654 [INPUT_BUTTON_WHEEL_DOWN] = 0x10,
1655 };
1656 QemuConsole *con = vs->vd->dcl.con;
Peter Lievenbea60dd2014-06-30 10:57:51 +02001657 int width = pixman_image_get_width(vs->vd->server);
1658 int height = pixman_image_get_height(vs->vd->server);
bellard24236862006-04-30 21:28:36 +00001659
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001660 if (vs->last_bmask != button_mask) {
1661 qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
1662 vs->last_bmask = button_mask;
1663 }
bellard564c3372007-02-05 20:14:10 +00001664
1665 if (vs->absolute) {
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001666 qemu_input_queue_abs(con, INPUT_AXIS_X, x, width);
1667 qemu_input_queue_abs(con, INPUT_AXIS_Y, y, height);
aliguori29fa4ed2009-02-02 15:58:29 +00001668 } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001669 qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF);
1670 qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF);
bellard24236862006-04-30 21:28:36 +00001671 } else {
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001672 if (vs->last_x != -1) {
1673 qemu_input_queue_rel(con, INPUT_AXIS_X, x - vs->last_x);
1674 qemu_input_queue_rel(con, INPUT_AXIS_Y, y - vs->last_y);
1675 }
aliguori28a76be2009-03-06 20:27:40 +00001676 vs->last_x = x;
1677 vs->last_y = y;
bellard24236862006-04-30 21:28:36 +00001678 }
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001679 qemu_input_event_sync();
bellard24236862006-04-30 21:28:36 +00001680}
1681
bellard64f5a132006-08-24 20:36:44 +00001682static void reset_keys(VncState *vs)
1683{
1684 int i;
1685 for(i = 0; i < 256; i++) {
1686 if (vs->modifiers_state[i]) {
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001687 qemu_input_event_send_key_number(vs->vd->dcl.con, i, false);
bellard64f5a132006-08-24 20:36:44 +00001688 vs->modifiers_state[i] = 0;
1689 }
1690 }
1691}
1692
balroga528b802007-10-30 22:38:53 +00001693static void press_key(VncState *vs, int keysym)
1694{
Samuel Thibault44bb61c2010-02-28 21:03:00 +01001695 int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001696 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
Gerd Hoffmann2deb4ac2014-06-02 13:15:05 +02001697 qemu_input_event_send_key_delay(0);
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001698 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
Gerd Hoffmann2deb4ac2014-06-02 13:15:05 +02001699 qemu_input_event_send_key_delay(0);
balroga528b802007-10-30 22:38:53 +00001700}
1701
Lei Liab99e5c2013-04-25 13:29:10 +08001702static int current_led_state(VncState *vs)
1703{
1704 int ledstate = 0;
1705
1706 if (vs->modifiers_state[0x46]) {
1707 ledstate |= QEMU_SCROLL_LOCK_LED;
1708 }
1709 if (vs->modifiers_state[0x45]) {
1710 ledstate |= QEMU_NUM_LOCK_LED;
1711 }
1712 if (vs->modifiers_state[0x3a]) {
1713 ledstate |= QEMU_CAPS_LOCK_LED;
1714 }
1715
1716 return ledstate;
1717}
1718
1719static void vnc_led_state_change(VncState *vs)
1720{
1721 int ledstate = 0;
1722
1723 if (!vnc_has_feature(vs, VNC_FEATURE_LED_STATE)) {
1724 return;
1725 }
1726
1727 ledstate = current_led_state(vs);
1728 vnc_lock_output(vs);
1729 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1730 vnc_write_u8(vs, 0);
1731 vnc_write_u16(vs, 1);
1732 vnc_framebuffer_update(vs, 0, 0, 1, 1, VNC_ENCODING_LED_STATE);
1733 vnc_write_u8(vs, ledstate);
1734 vnc_unlock_output(vs);
1735 vnc_flush(vs);
1736}
1737
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001738static void kbd_leds(void *opaque, int ledstate)
1739{
1740 VncState *vs = opaque;
Lei Li96f3d172013-04-25 13:29:09 +08001741 int caps, num, scr;
Lei Li1483adc2013-05-15 16:20:40 +08001742 bool has_changed = (ledstate != current_led_state(vs));
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001743
Gerd Hoffmann40066172014-05-21 13:18:20 +02001744 trace_vnc_key_guest_leds((ledstate & QEMU_CAPS_LOCK_LED),
1745 (ledstate & QEMU_NUM_LOCK_LED),
1746 (ledstate & QEMU_SCROLL_LOCK_LED));
1747
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001748 caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
1749 num = ledstate & QEMU_NUM_LOCK_LED ? 1 : 0;
Lei Li96f3d172013-04-25 13:29:09 +08001750 scr = ledstate & QEMU_SCROLL_LOCK_LED ? 1 : 0;
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001751
1752 if (vs->modifiers_state[0x3a] != caps) {
1753 vs->modifiers_state[0x3a] = caps;
1754 }
1755 if (vs->modifiers_state[0x45] != num) {
1756 vs->modifiers_state[0x45] = num;
1757 }
Lei Li96f3d172013-04-25 13:29:09 +08001758 if (vs->modifiers_state[0x46] != scr) {
1759 vs->modifiers_state[0x46] = scr;
1760 }
Lei Liab99e5c2013-04-25 13:29:10 +08001761
1762 /* Sending the current led state message to the client */
Lei Li1483adc2013-05-15 16:20:40 +08001763 if (has_changed) {
Lei Liab99e5c2013-04-25 13:29:10 +08001764 vnc_led_state_change(vs);
1765 }
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001766}
1767
aliguori9ca313a2008-08-23 23:27:37 +00001768static void do_key_event(VncState *vs, int down, int keycode, int sym)
bellard24236862006-04-30 21:28:36 +00001769{
bellard64f5a132006-08-24 20:36:44 +00001770 /* QEMU console switch */
1771 switch(keycode) {
1772 case 0x2a: /* Left Shift */
1773 case 0x36: /* Right Shift */
1774 case 0x1d: /* Left CTRL */
1775 case 0x9d: /* Right CTRL */
1776 case 0x38: /* Left ALT */
1777 case 0xb8: /* Right ALT */
1778 if (down)
1779 vs->modifiers_state[keycode] = 1;
1780 else
1781 vs->modifiers_state[keycode] = 0;
1782 break;
ths5fafdf22007-09-16 21:08:06 +00001783 case 0x02 ... 0x0a: /* '1' to '9' keys */
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +02001784 if (vs->vd->dcl.con == NULL &&
1785 down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
bellard64f5a132006-08-24 20:36:44 +00001786 /* Reset the modifiers sent to the current console */
1787 reset_keys(vs);
1788 console_select(keycode - 0x02);
1789 return;
1790 }
1791 break;
aliguori28a76be2009-03-06 20:27:40 +00001792 case 0x3a: /* CapsLock */
1793 case 0x45: /* NumLock */
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001794 if (down)
balroga528b802007-10-30 22:38:53 +00001795 vs->modifiers_state[keycode] ^= 1;
1796 break;
1797 }
1798
Lei Lie7b2aac2013-04-25 13:29:11 +08001799 /* Turn off the lock state sync logic if the client support the led
1800 state extension.
1801 */
Gerd Hoffmann98920882011-01-14 10:56:54 +01001802 if (down && vs->vd->lock_key_sync &&
Lei Lie7b2aac2013-04-25 13:29:11 +08001803 !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01001804 keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
balroga528b802007-10-30 22:38:53 +00001805 /* If the numlock state needs to change then simulate an additional
1806 keypress before sending this one. This will happen if the user
1807 toggles numlock away from the VNC window.
1808 */
aliguori753b4052009-02-16 14:59:30 +00001809 if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
balroga528b802007-10-30 22:38:53 +00001810 if (!vs->modifiers_state[0x45]) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001811 trace_vnc_key_sync_numlock(true);
balroga528b802007-10-30 22:38:53 +00001812 vs->modifiers_state[0x45] = 1;
1813 press_key(vs, 0xff7f);
1814 }
1815 } else {
1816 if (vs->modifiers_state[0x45]) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001817 trace_vnc_key_sync_numlock(false);
balroga528b802007-10-30 22:38:53 +00001818 vs->modifiers_state[0x45] = 0;
1819 press_key(vs, 0xff7f);
1820 }
1821 }
bellard64f5a132006-08-24 20:36:44 +00001822 }
bellard24236862006-04-30 21:28:36 +00001823
Gerd Hoffmann98920882011-01-14 10:56:54 +01001824 if (down && vs->vd->lock_key_sync &&
Lei Lie7b2aac2013-04-25 13:29:11 +08001825 !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01001826 ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001827 /* If the capslock state needs to change then simulate an additional
1828 keypress before sending this one. This will happen if the user
1829 toggles capslock away from the VNC window.
1830 */
1831 int uppercase = !!(sym >= 'A' && sym <= 'Z');
1832 int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
1833 int capslock = !!(vs->modifiers_state[0x3a]);
1834 if (capslock) {
1835 if (uppercase == shift) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001836 trace_vnc_key_sync_capslock(false);
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001837 vs->modifiers_state[0x3a] = 0;
1838 press_key(vs, 0xffe5);
1839 }
1840 } else {
1841 if (uppercase != shift) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001842 trace_vnc_key_sync_capslock(true);
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001843 vs->modifiers_state[0x3a] = 1;
1844 press_key(vs, 0xffe5);
1845 }
1846 }
1847 }
1848
Gerd Hoffmann81c0d5a2013-03-14 14:27:08 +01001849 if (qemu_console_is_graphic(NULL)) {
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001850 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
bellard64f5a132006-08-24 20:36:44 +00001851 } else {
Gerd Hoffmanne26437c2011-11-08 10:02:16 +01001852 bool numlock = vs->modifiers_state[0x45];
1853 bool control = (vs->modifiers_state[0x1d] ||
1854 vs->modifiers_state[0x9d]);
bellard64f5a132006-08-24 20:36:44 +00001855 /* QEMU console emulation */
1856 if (down) {
1857 switch (keycode) {
1858 case 0x2a: /* Left Shift */
1859 case 0x36: /* Right Shift */
1860 case 0x1d: /* Left CTRL */
1861 case 0x9d: /* Right CTRL */
1862 case 0x38: /* Left ALT */
1863 case 0xb8: /* Right ALT */
1864 break;
1865 case 0xc8:
1866 kbd_put_keysym(QEMU_KEY_UP);
1867 break;
1868 case 0xd0:
1869 kbd_put_keysym(QEMU_KEY_DOWN);
1870 break;
1871 case 0xcb:
1872 kbd_put_keysym(QEMU_KEY_LEFT);
1873 break;
1874 case 0xcd:
1875 kbd_put_keysym(QEMU_KEY_RIGHT);
1876 break;
1877 case 0xd3:
1878 kbd_put_keysym(QEMU_KEY_DELETE);
1879 break;
1880 case 0xc7:
1881 kbd_put_keysym(QEMU_KEY_HOME);
1882 break;
1883 case 0xcf:
1884 kbd_put_keysym(QEMU_KEY_END);
1885 break;
1886 case 0xc9:
1887 kbd_put_keysym(QEMU_KEY_PAGEUP);
1888 break;
1889 case 0xd1:
1890 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1891 break;
Gerd Hoffmannbb0a18e2009-06-11 11:32:14 +02001892
1893 case 0x47:
1894 kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
1895 break;
1896 case 0x48:
1897 kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
1898 break;
1899 case 0x49:
1900 kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
1901 break;
1902 case 0x4b:
1903 kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
1904 break;
1905 case 0x4c:
1906 kbd_put_keysym('5');
1907 break;
1908 case 0x4d:
1909 kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
1910 break;
1911 case 0x4f:
1912 kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
1913 break;
1914 case 0x50:
1915 kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
1916 break;
1917 case 0x51:
1918 kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
1919 break;
1920 case 0x52:
1921 kbd_put_keysym('0');
1922 break;
1923 case 0x53:
1924 kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
1925 break;
1926
1927 case 0xb5:
1928 kbd_put_keysym('/');
1929 break;
1930 case 0x37:
1931 kbd_put_keysym('*');
1932 break;
1933 case 0x4a:
1934 kbd_put_keysym('-');
1935 break;
1936 case 0x4e:
1937 kbd_put_keysym('+');
1938 break;
1939 case 0x9c:
1940 kbd_put_keysym('\n');
1941 break;
1942
bellard64f5a132006-08-24 20:36:44 +00001943 default:
Gerd Hoffmanne26437c2011-11-08 10:02:16 +01001944 if (control) {
1945 kbd_put_keysym(sym & 0x1f);
1946 } else {
1947 kbd_put_keysym(sym);
1948 }
bellard64f5a132006-08-24 20:36:44 +00001949 break;
1950 }
1951 }
1952 }
bellard24236862006-04-30 21:28:36 +00001953}
1954
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001955static void vnc_release_modifiers(VncState *vs)
1956{
1957 static const int keycodes[] = {
1958 /* shift, control, alt keys, both left & right */
1959 0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8,
1960 };
1961 int i, keycode;
1962
Gerd Hoffmann81c0d5a2013-03-14 14:27:08 +01001963 if (!qemu_console_is_graphic(NULL)) {
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001964 return;
1965 }
1966 for (i = 0; i < ARRAY_SIZE(keycodes); i++) {
1967 keycode = keycodes[i];
1968 if (!vs->modifiers_state[keycode]) {
1969 continue;
1970 }
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001971 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001972 }
1973}
1974
Gerd Hoffmann40066172014-05-21 13:18:20 +02001975static const char *code2name(int keycode)
1976{
1977 return QKeyCode_lookup[qemu_input_key_number_to_qcode(keycode)];
1978}
1979
bellardbdbd7672006-05-01 21:44:22 +00001980static void key_event(VncState *vs, int down, uint32_t sym)
1981{
aliguori9ca313a2008-08-23 23:27:37 +00001982 int keycode;
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001983 int lsym = sym;
aliguori9ca313a2008-08-23 23:27:37 +00001984
Gerd Hoffmann81c0d5a2013-03-14 14:27:08 +01001985 if (lsym >= 'A' && lsym <= 'Z' && qemu_console_is_graphic(NULL)) {
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001986 lsym = lsym - 'A' + 'a';
1987 }
aliguori9ca313a2008-08-23 23:27:37 +00001988
Samuel Thibault44bb61c2010-02-28 21:03:00 +01001989 keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
Gerd Hoffmann40066172014-05-21 13:18:20 +02001990 trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
aliguori9ca313a2008-08-23 23:27:37 +00001991 do_key_event(vs, down, keycode, sym);
1992}
1993
1994static void ext_key_event(VncState *vs, int down,
1995 uint32_t sym, uint16_t keycode)
1996{
1997 /* if the user specifies a keyboard layout, always use it */
Gerd Hoffmann40066172014-05-21 13:18:20 +02001998 if (keyboard_layout) {
aliguori9ca313a2008-08-23 23:27:37 +00001999 key_event(vs, down, sym);
Gerd Hoffmann40066172014-05-21 13:18:20 +02002000 } else {
2001 trace_vnc_key_event_ext(down, sym, keycode, code2name(keycode));
aliguori9ca313a2008-08-23 23:27:37 +00002002 do_key_event(vs, down, keycode, sym);
Gerd Hoffmann40066172014-05-21 13:18:20 +02002003 }
bellardbdbd7672006-05-01 21:44:22 +00002004}
2005
bellard24236862006-04-30 21:28:36 +00002006static void framebuffer_update_request(VncState *vs, int incremental,
Peter Lievenbea60dd2014-06-30 10:57:51 +02002007 int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +00002008{
Peter Lievenbea60dd2014-06-30 10:57:51 +02002009 int width = pixman_image_get_width(vs->vd->server);
2010 int height = pixman_image_get_height(vs->vd->server);
thscf2d3852007-04-29 01:53:20 +00002011
bellard24236862006-04-30 21:28:36 +00002012 vs->need_update = 1;
Peter Lievenbea60dd2014-06-30 10:57:51 +02002013
2014 if (incremental) {
2015 return;
bellard24236862006-04-30 21:28:36 +00002016 }
Peter Lievenbea60dd2014-06-30 10:57:51 +02002017
Stephan Kulow07535a82014-07-23 16:03:14 +02002018 vs->force_update = 1;
Peter Lievenbea60dd2014-06-30 10:57:51 +02002019 vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h);
bellard24236862006-04-30 21:28:36 +00002020}
2021
aliguori9ca313a2008-08-23 23:27:37 +00002022static void send_ext_key_event_ack(VncState *vs)
2023{
Corentin Charybd023f92010-07-07 20:58:02 +02002024 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002025 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
aliguori9ca313a2008-08-23 23:27:37 +00002026 vnc_write_u8(vs, 0);
2027 vnc_write_u16(vs, 1);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01002028 vnc_framebuffer_update(vs, 0, 0,
Peter Lievenbea60dd2014-06-30 10:57:51 +02002029 pixman_image_get_width(vs->vd->server),
2030 pixman_image_get_height(vs->vd->server),
aliguori29fa4ed2009-02-02 15:58:29 +00002031 VNC_ENCODING_EXT_KEY_EVENT);
Corentin Charybd023f92010-07-07 20:58:02 +02002032 vnc_unlock_output(vs);
aliguori9ca313a2008-08-23 23:27:37 +00002033 vnc_flush(vs);
2034}
2035
malc429a8ed2008-12-01 20:57:48 +00002036static void send_ext_audio_ack(VncState *vs)
2037{
Corentin Charybd023f92010-07-07 20:58:02 +02002038 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002039 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
malc429a8ed2008-12-01 20:57:48 +00002040 vnc_write_u8(vs, 0);
2041 vnc_write_u16(vs, 1);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01002042 vnc_framebuffer_update(vs, 0, 0,
Peter Lievenbea60dd2014-06-30 10:57:51 +02002043 pixman_image_get_width(vs->vd->server),
2044 pixman_image_get_height(vs->vd->server),
aliguori29fa4ed2009-02-02 15:58:29 +00002045 VNC_ENCODING_AUDIO);
Corentin Charybd023f92010-07-07 20:58:02 +02002046 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +00002047 vnc_flush(vs);
2048}
2049
bellard24236862006-04-30 21:28:36 +00002050static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
2051{
2052 int i;
aliguori29fa4ed2009-02-02 15:58:29 +00002053 unsigned int enc = 0;
bellard24236862006-04-30 21:28:36 +00002054
aliguori29fa4ed2009-02-02 15:58:29 +00002055 vs->features = 0;
Corentin Charya9f20d32010-05-19 09:24:01 +02002056 vs->vnc_encoding = 0;
Corentin Charyd1af0e02010-07-07 20:57:59 +02002057 vs->tight.compression = 9;
2058 vs->tight.quality = -1; /* Lossless by default */
bellard564c3372007-02-05 20:14:10 +00002059 vs->absolute = -1;
bellard24236862006-04-30 21:28:36 +00002060
Corentin Chary8a0f0d02010-05-19 09:24:02 +02002061 /*
2062 * Start from the end because the encodings are sent in order of preference.
Dong Xu Wange5bed752011-11-22 18:06:24 +08002063 * This way the preferred encoding (first encoding defined in the array)
Corentin Chary8a0f0d02010-05-19 09:24:02 +02002064 * will be set at the end of the loop.
2065 */
bellard24236862006-04-30 21:28:36 +00002066 for (i = n_encodings - 1; i >= 0; i--) {
aliguori29fa4ed2009-02-02 15:58:29 +00002067 enc = encodings[i];
2068 switch (enc) {
2069 case VNC_ENCODING_RAW:
Corentin Charya9f20d32010-05-19 09:24:01 +02002070 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00002071 break;
2072 case VNC_ENCODING_COPYRECT:
aliguori753b4052009-02-16 14:59:30 +00002073 vs->features |= VNC_FEATURE_COPYRECT_MASK;
aliguori29fa4ed2009-02-02 15:58:29 +00002074 break;
2075 case VNC_ENCODING_HEXTILE:
2076 vs->features |= VNC_FEATURE_HEXTILE_MASK;
Corentin Charya9f20d32010-05-19 09:24:01 +02002077 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00002078 break;
Corentin Chary380282b2010-05-19 09:24:10 +02002079 case VNC_ENCODING_TIGHT:
2080 vs->features |= VNC_FEATURE_TIGHT_MASK;
2081 vs->vnc_encoding = enc;
2082 break;
Joel Martinfe3e7f22012-05-16 12:54:25 +00002083#ifdef CONFIG_VNC_PNG
Corentin Charyefe556a2010-07-07 20:57:56 +02002084 case VNC_ENCODING_TIGHT_PNG:
2085 vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
2086 vs->vnc_encoding = enc;
2087 break;
Joel Martinfe3e7f22012-05-16 12:54:25 +00002088#endif
aliguori059cef42009-02-02 15:58:54 +00002089 case VNC_ENCODING_ZLIB:
2090 vs->features |= VNC_FEATURE_ZLIB_MASK;
Corentin Charya9f20d32010-05-19 09:24:01 +02002091 vs->vnc_encoding = enc;
aliguori059cef42009-02-02 15:58:54 +00002092 break;
Corentin Chary148954f2011-02-04 09:06:01 +01002093 case VNC_ENCODING_ZRLE:
2094 vs->features |= VNC_FEATURE_ZRLE_MASK;
2095 vs->vnc_encoding = enc;
2096 break;
2097 case VNC_ENCODING_ZYWRLE:
2098 vs->features |= VNC_FEATURE_ZYWRLE_MASK;
2099 vs->vnc_encoding = enc;
2100 break;
aliguori29fa4ed2009-02-02 15:58:29 +00002101 case VNC_ENCODING_DESKTOPRESIZE:
2102 vs->features |= VNC_FEATURE_RESIZE_MASK;
2103 break;
2104 case VNC_ENCODING_POINTER_TYPE_CHANGE:
2105 vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
2106 break;
Gerd Hoffmannd467b672010-05-21 11:54:34 +02002107 case VNC_ENCODING_RICH_CURSOR:
2108 vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
2109 break;
aliguori29fa4ed2009-02-02 15:58:29 +00002110 case VNC_ENCODING_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00002111 send_ext_key_event_ack(vs);
2112 break;
aliguori29fa4ed2009-02-02 15:58:29 +00002113 case VNC_ENCODING_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00002114 send_ext_audio_ack(vs);
2115 break;
aliguori29fa4ed2009-02-02 15:58:29 +00002116 case VNC_ENCODING_WMVi:
2117 vs->features |= VNC_FEATURE_WMVI_MASK;
aliguorica4cca42008-09-15 16:05:16 +00002118 break;
Lei Liab99e5c2013-04-25 13:29:10 +08002119 case VNC_ENCODING_LED_STATE:
2120 vs->features |= VNC_FEATURE_LED_STATE_MASK;
2121 break;
aliguorifb437312009-02-02 15:58:43 +00002122 case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
Corentin Charyd1af0e02010-07-07 20:57:59 +02002123 vs->tight.compression = (enc & 0x0F);
aliguorifb437312009-02-02 15:58:43 +00002124 break;
2125 case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
Corentin Charyb31f5192011-02-04 09:05:54 +01002126 if (vs->vd->lossy) {
2127 vs->tight.quality = (enc & 0x0F);
2128 }
aliguorifb437312009-02-02 15:58:43 +00002129 break;
aliguori29fa4ed2009-02-02 15:58:29 +00002130 default:
2131 VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
2132 break;
2133 }
bellard24236862006-04-30 21:28:36 +00002134 }
Gerd Hoffmann6356e472010-05-25 18:25:17 +02002135 vnc_desktop_resize(vs);
Jan Kiszka9e8dd452011-06-20 14:06:26 +02002136 check_pointer_type_change(&vs->mouse_mode_notifier, NULL);
Lei Liab99e5c2013-04-25 13:29:10 +08002137 vnc_led_state_change(vs);
bellard24236862006-04-30 21:28:36 +00002138}
2139
aliguori6cec5482009-01-15 22:17:38 +00002140static void set_pixel_conversion(VncState *vs)
2141{
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002142 pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf);
2143
2144 if (fmt == VNC_SERVER_FB_FORMAT) {
aliguori6cec5482009-01-15 22:17:38 +00002145 vs->write_pixels = vnc_write_pixels_copy;
Corentin Chary70a45682010-05-03 14:31:34 +02002146 vnc_hextile_set_pixel_conversion(vs, 0);
aliguori6cec5482009-01-15 22:17:38 +00002147 } else {
2148 vs->write_pixels = vnc_write_pixels_generic;
Corentin Chary70a45682010-05-03 14:31:34 +02002149 vnc_hextile_set_pixel_conversion(vs, 1);
aliguori6cec5482009-01-15 22:17:38 +00002150 }
2151}
2152
bellard24236862006-04-30 21:28:36 +00002153static void set_pixel_format(VncState *vs,
aliguori28a76be2009-03-06 20:27:40 +00002154 int bits_per_pixel, int depth,
2155 int big_endian_flag, int true_color_flag,
2156 int red_max, int green_max, int blue_max,
2157 int red_shift, int green_shift, int blue_shift)
bellard24236862006-04-30 21:28:36 +00002158{
bellard35127792006-05-14 18:11:49 +00002159 if (!true_color_flag) {
aliguori28a76be2009-03-06 20:27:40 +00002160 vnc_client_error(vs);
bellard35127792006-05-14 18:11:49 +00002161 return;
2162 }
aliguori7eac3a82008-09-15 16:03:41 +00002163
Petr Matouseke6908bf2014-10-27 12:41:44 +01002164 switch (bits_per_pixel) {
2165 case 8:
2166 case 16:
2167 case 32:
2168 break;
2169 default:
2170 vnc_client_error(vs);
2171 return;
2172 }
2173
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002174 vs->client_pf.rmax = red_max;
2175 vs->client_pf.rbits = hweight_long(red_max);
2176 vs->client_pf.rshift = red_shift;
2177 vs->client_pf.rmask = red_max << red_shift;
2178 vs->client_pf.gmax = green_max;
2179 vs->client_pf.gbits = hweight_long(green_max);
2180 vs->client_pf.gshift = green_shift;
2181 vs->client_pf.gmask = green_max << green_shift;
2182 vs->client_pf.bmax = blue_max;
2183 vs->client_pf.bbits = hweight_long(blue_max);
2184 vs->client_pf.bshift = blue_shift;
2185 vs->client_pf.bmask = blue_max << blue_shift;
2186 vs->client_pf.bits_per_pixel = bits_per_pixel;
2187 vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
2188 vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
2189 vs->client_be = big_endian_flag;
bellard24236862006-04-30 21:28:36 +00002190
aliguori6cec5482009-01-15 22:17:38 +00002191 set_pixel_conversion(vs);
bellard24236862006-04-30 21:28:36 +00002192
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +02002193 graphic_hw_invalidate(vs->vd->dcl.con);
2194 graphic_hw_update(vs->vd->dcl.con);
bellard24236862006-04-30 21:28:36 +00002195}
2196
aliguorica4cca42008-09-15 16:05:16 +00002197static void pixel_format_message (VncState *vs) {
2198 char pad[3] = { 0, 0, 0 };
2199
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002200 vs->client_pf = qemu_default_pixelformat(32);
2201
2202 vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */
2203 vnc_write_u8(vs, vs->client_pf.depth); /* depth */
aliguorica4cca42008-09-15 16:05:16 +00002204
Juan Quintelae2542fe2009-07-27 16:13:06 +02002205#ifdef HOST_WORDS_BIGENDIAN
aliguorica4cca42008-09-15 16:05:16 +00002206 vnc_write_u8(vs, 1); /* big-endian-flag */
2207#else
2208 vnc_write_u8(vs, 0); /* big-endian-flag */
2209#endif
2210 vnc_write_u8(vs, 1); /* true-color-flag */
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002211 vnc_write_u16(vs, vs->client_pf.rmax); /* red-max */
2212 vnc_write_u16(vs, vs->client_pf.gmax); /* green-max */
2213 vnc_write_u16(vs, vs->client_pf.bmax); /* blue-max */
2214 vnc_write_u8(vs, vs->client_pf.rshift); /* red-shift */
2215 vnc_write_u8(vs, vs->client_pf.gshift); /* green-shift */
2216 vnc_write_u8(vs, vs->client_pf.bshift); /* blue-shift */
2217 vnc_write(vs, pad, 3); /* padding */
Corentin Chary70a45682010-05-03 14:31:34 +02002218
2219 vnc_hextile_set_pixel_conversion(vs, 0);
aliguorica4cca42008-09-15 16:05:16 +00002220 vs->write_pixels = vnc_write_pixels_copy;
aliguorica4cca42008-09-15 16:05:16 +00002221}
2222
aliguori753b4052009-02-16 14:59:30 +00002223static void vnc_colordepth(VncState *vs)
aliguori7eac3a82008-09-15 16:03:41 +00002224{
aliguori753b4052009-02-16 14:59:30 +00002225 if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
aliguorica4cca42008-09-15 16:05:16 +00002226 /* Sending a WMVi message to notify the client*/
Corentin Charybd023f92010-07-07 20:58:02 +02002227 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002228 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
aliguorica4cca42008-09-15 16:05:16 +00002229 vnc_write_u8(vs, 0);
2230 vnc_write_u16(vs, 1); /* number of rects */
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01002231 vnc_framebuffer_update(vs, 0, 0,
Peter Lievenbea60dd2014-06-30 10:57:51 +02002232 pixman_image_get_width(vs->vd->server),
2233 pixman_image_get_height(vs->vd->server),
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01002234 VNC_ENCODING_WMVi);
aliguorica4cca42008-09-15 16:05:16 +00002235 pixel_format_message(vs);
Corentin Charybd023f92010-07-07 20:58:02 +02002236 vnc_unlock_output(vs);
aliguorica4cca42008-09-15 16:05:16 +00002237 vnc_flush(vs);
aliguori7eac3a82008-09-15 16:03:41 +00002238 } else {
aliguori6cec5482009-01-15 22:17:38 +00002239 set_pixel_conversion(vs);
aliguori7eac3a82008-09-15 16:03:41 +00002240 }
2241}
2242
ths60fe76f2007-12-16 03:02:09 +00002243static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00002244{
2245 int i;
2246 uint16_t limit;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002247 VncDisplay *vd = vs->vd;
2248
2249 if (data[0] > 3) {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002250 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002251 }
bellard24236862006-04-30 21:28:36 +00002252
2253 switch (data[0]) {
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002254 case VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
aliguori28a76be2009-03-06 20:27:40 +00002255 if (len == 1)
2256 return 20;
bellard24236862006-04-30 21:28:36 +00002257
aliguori28a76be2009-03-06 20:27:40 +00002258 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
2259 read_u8(data, 6), read_u8(data, 7),
2260 read_u16(data, 8), read_u16(data, 10),
2261 read_u16(data, 12), read_u8(data, 14),
2262 read_u8(data, 15), read_u8(data, 16));
2263 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002264 case VNC_MSG_CLIENT_SET_ENCODINGS:
aliguori28a76be2009-03-06 20:27:40 +00002265 if (len == 1)
2266 return 4;
bellard24236862006-04-30 21:28:36 +00002267
aliguori28a76be2009-03-06 20:27:40 +00002268 if (len == 4) {
aliguori69dd5c92008-12-22 21:06:23 +00002269 limit = read_u16(data, 2);
2270 if (limit > 0)
2271 return 4 + (limit * 4);
2272 } else
2273 limit = read_u16(data, 2);
bellard24236862006-04-30 21:28:36 +00002274
aliguori28a76be2009-03-06 20:27:40 +00002275 for (i = 0; i < limit; i++) {
2276 int32_t val = read_s32(data, 4 + (i * 4));
2277 memcpy(data + 4 + (i * 4), &val, sizeof(val));
2278 }
bellard24236862006-04-30 21:28:36 +00002279
aliguori28a76be2009-03-06 20:27:40 +00002280 set_encodings(vs, (int32_t *)(data + 4), limit);
2281 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002282 case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
aliguori28a76be2009-03-06 20:27:40 +00002283 if (len == 1)
2284 return 10;
bellard24236862006-04-30 21:28:36 +00002285
aliguori28a76be2009-03-06 20:27:40 +00002286 framebuffer_update_request(vs,
2287 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
2288 read_u16(data, 6), read_u16(data, 8));
2289 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002290 case VNC_MSG_CLIENT_KEY_EVENT:
aliguori28a76be2009-03-06 20:27:40 +00002291 if (len == 1)
2292 return 8;
bellard24236862006-04-30 21:28:36 +00002293
aliguori28a76be2009-03-06 20:27:40 +00002294 key_event(vs, read_u8(data, 1), read_u32(data, 4));
2295 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002296 case VNC_MSG_CLIENT_POINTER_EVENT:
aliguori28a76be2009-03-06 20:27:40 +00002297 if (len == 1)
2298 return 6;
bellard24236862006-04-30 21:28:36 +00002299
aliguori28a76be2009-03-06 20:27:40 +00002300 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
2301 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002302 case VNC_MSG_CLIENT_CUT_TEXT:
Peter Lievenf9a70e72014-06-30 10:07:54 +02002303 if (len == 1) {
aliguori28a76be2009-03-06 20:27:40 +00002304 return 8;
Peter Lievenf9a70e72014-06-30 10:07:54 +02002305 }
aliguori28a76be2009-03-06 20:27:40 +00002306 if (len == 8) {
thsbaa76662007-09-13 12:41:42 +00002307 uint32_t dlen = read_u32(data, 4);
Peter Lievenf9a70e72014-06-30 10:07:54 +02002308 if (dlen > (1 << 20)) {
2309 error_report("vnc: client_cut_text msg payload has %u bytes"
2310 " which exceeds our limit of 1MB.", dlen);
2311 vnc_client_error(vs);
2312 break;
2313 }
2314 if (dlen > 0) {
thsbaa76662007-09-13 12:41:42 +00002315 return 8 + dlen;
Peter Lievenf9a70e72014-06-30 10:07:54 +02002316 }
thsbaa76662007-09-13 12:41:42 +00002317 }
bellard24236862006-04-30 21:28:36 +00002318
aliguori28a76be2009-03-06 20:27:40 +00002319 client_cut_text(vs, read_u32(data, 4), data + 8);
2320 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002321 case VNC_MSG_CLIENT_QEMU:
aliguori9ca313a2008-08-23 23:27:37 +00002322 if (len == 1)
2323 return 2;
2324
2325 switch (read_u8(data, 1)) {
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002326 case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00002327 if (len == 2)
2328 return 12;
2329
2330 ext_key_event(vs, read_u16(data, 2),
2331 read_u32(data, 4), read_u32(data, 8));
2332 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002333 case VNC_MSG_CLIENT_QEMU_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00002334 if (len == 2)
2335 return 4;
2336
2337 switch (read_u16 (data, 2)) {
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002338 case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
malc429a8ed2008-12-01 20:57:48 +00002339 audio_add(vs);
2340 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002341 case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
malc429a8ed2008-12-01 20:57:48 +00002342 audio_del(vs);
2343 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002344 case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
malc429a8ed2008-12-01 20:57:48 +00002345 if (len == 4)
2346 return 10;
2347 switch (read_u8(data, 4)) {
2348 case 0: vs->as.fmt = AUD_FMT_U8; break;
2349 case 1: vs->as.fmt = AUD_FMT_S8; break;
2350 case 2: vs->as.fmt = AUD_FMT_U16; break;
2351 case 3: vs->as.fmt = AUD_FMT_S16; break;
2352 case 4: vs->as.fmt = AUD_FMT_U32; break;
2353 case 5: vs->as.fmt = AUD_FMT_S32; break;
2354 default:
Daniel P. Berrange153130c2015-03-17 13:42:54 +00002355 VNC_DEBUG("Invalid audio format %d\n", read_u8(data, 4));
malc429a8ed2008-12-01 20:57:48 +00002356 vnc_client_error(vs);
2357 break;
2358 }
2359 vs->as.nchannels = read_u8(data, 5);
2360 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
Daniel P. Berrange153130c2015-03-17 13:42:54 +00002361 VNC_DEBUG("Invalid audio channel coount %d\n",
2362 read_u8(data, 5));
malc429a8ed2008-12-01 20:57:48 +00002363 vnc_client_error(vs);
2364 break;
2365 }
2366 vs->as.freq = read_u32(data, 6);
2367 break;
2368 default:
Daniel P. Berrange153130c2015-03-17 13:42:54 +00002369 VNC_DEBUG("Invalid audio message %d\n", read_u8(data, 4));
malc429a8ed2008-12-01 20:57:48 +00002370 vnc_client_error(vs);
2371 break;
2372 }
2373 break;
2374
aliguori9ca313a2008-08-23 23:27:37 +00002375 default:
Daniel P. Berrange153130c2015-03-17 13:42:54 +00002376 VNC_DEBUG("Msg: %d\n", read_u16(data, 0));
aliguori9ca313a2008-08-23 23:27:37 +00002377 vnc_client_error(vs);
2378 break;
2379 }
2380 break;
bellard24236862006-04-30 21:28:36 +00002381 default:
Daniel P. Berrange153130c2015-03-17 13:42:54 +00002382 VNC_DEBUG("Msg: %d\n", data[0]);
aliguori28a76be2009-03-06 20:27:40 +00002383 vnc_client_error(vs);
2384 break;
bellard24236862006-04-30 21:28:36 +00002385 }
ths5fafdf22007-09-16 21:08:06 +00002386
bellard24236862006-04-30 21:28:36 +00002387 vnc_read_when(vs, protocol_client_msg, 1);
2388 return 0;
2389}
2390
ths60fe76f2007-12-16 03:02:09 +00002391static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00002392{
thsc35734b2007-03-19 15:17:08 +00002393 char buf[1024];
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01002394 VncShareMode mode;
thsc35734b2007-03-19 15:17:08 +00002395 int size;
bellard24236862006-04-30 21:28:36 +00002396
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01002397 mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE;
2398 switch (vs->vd->share_policy) {
2399 case VNC_SHARE_POLICY_IGNORE:
2400 /*
2401 * Ignore the shared flag. Nothing to do here.
2402 *
2403 * Doesn't conform to the rfb spec but is traditional qemu
2404 * behavior, thus left here as option for compatibility
2405 * reasons.
2406 */
2407 break;
2408 case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE:
2409 /*
2410 * Policy: Allow clients ask for exclusive access.
2411 *
2412 * Implementation: When a client asks for exclusive access,
2413 * disconnect all others. Shared connects are allowed as long
2414 * as no exclusive connection exists.
2415 *
2416 * This is how the rfb spec suggests to handle the shared flag.
2417 */
2418 if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
2419 VncState *client;
2420 QTAILQ_FOREACH(client, &vs->vd->clients, next) {
2421 if (vs == client) {
2422 continue;
2423 }
2424 if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE &&
2425 client->share_mode != VNC_SHARE_MODE_SHARED) {
2426 continue;
2427 }
2428 vnc_disconnect_start(client);
2429 }
2430 }
2431 if (mode == VNC_SHARE_MODE_SHARED) {
2432 if (vs->vd->num_exclusive > 0) {
2433 vnc_disconnect_start(vs);
2434 return 0;
2435 }
2436 }
2437 break;
2438 case VNC_SHARE_POLICY_FORCE_SHARED:
2439 /*
2440 * Policy: Shared connects only.
2441 * Implementation: Disallow clients asking for exclusive access.
2442 *
2443 * Useful for shared desktop sessions where you don't want
2444 * someone forgetting to say -shared when running the vnc
2445 * client disconnect everybody else.
2446 */
2447 if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
2448 vnc_disconnect_start(vs);
2449 return 0;
2450 }
2451 break;
2452 }
2453 vnc_set_share_mode(vs, mode);
2454
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +02002455 if (vs->vd->num_shared > vs->vd->connections_limit) {
2456 vnc_disconnect_start(vs);
2457 return 0;
2458 }
2459
Peter Lievenbea60dd2014-06-30 10:57:51 +02002460 vs->client_width = pixman_image_get_width(vs->vd->server);
2461 vs->client_height = pixman_image_get_height(vs->vd->server);
Gerd Hoffmann5862d192010-05-25 18:25:18 +02002462 vnc_write_u16(vs, vs->client_width);
2463 vnc_write_u16(vs, vs->client_height);
bellard24236862006-04-30 21:28:36 +00002464
aliguorica4cca42008-09-15 16:05:16 +00002465 pixel_format_message(vs);
bellard24236862006-04-30 21:28:36 +00002466
thsc35734b2007-03-19 15:17:08 +00002467 if (qemu_name)
2468 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
2469 else
2470 size = snprintf(buf, sizeof(buf), "QEMU");
2471
2472 vnc_write_u32(vs, size);
2473 vnc_write(vs, buf, size);
bellard24236862006-04-30 21:28:36 +00002474 vnc_flush(vs);
2475
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002476 vnc_client_cache_auth(vs);
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +02002477 vnc_qmp_event(vs, QAPI_EVENT_VNC_INITIALIZED);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002478
bellard24236862006-04-30 21:28:36 +00002479 vnc_read_when(vs, protocol_client_msg, 1);
2480
2481 return 0;
2482}
2483
aliguori5fb6c7a2009-03-06 20:27:23 +00002484void start_client_init(VncState *vs)
2485{
2486 vnc_read_when(vs, protocol_client_init, 1);
2487}
2488
ths70848512007-08-25 01:37:05 +00002489static void make_challenge(VncState *vs)
bellard24236862006-04-30 21:28:36 +00002490{
ths70848512007-08-25 01:37:05 +00002491 int i;
bellard24236862006-04-30 21:28:36 +00002492
ths70848512007-08-25 01:37:05 +00002493 srand(time(NULL)+getpid()+getpid()*987654+rand());
bellard24236862006-04-30 21:28:36 +00002494
ths70848512007-08-25 01:37:05 +00002495 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
2496 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
2497}
2498
ths60fe76f2007-12-16 03:02:09 +00002499static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002500{
ths60fe76f2007-12-16 03:02:09 +00002501 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
Daniel P. Berrange800567a2015-07-01 18:10:38 +01002502 size_t i, pwlen;
ths60fe76f2007-12-16 03:02:09 +00002503 unsigned char key[8];
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02002504 time_t now = time(NULL);
Gonglei60928452015-07-22 17:08:53 +08002505 QCryptoCipher *cipher = NULL;
Daniel P. Berrange800567a2015-07-01 18:10:38 +01002506 Error *err = NULL;
ths70848512007-08-25 01:37:05 +00002507
Anthony Liguori1cd20f82011-01-31 14:27:36 -06002508 if (!vs->vd->password) {
aliguori28a76be2009-03-06 20:27:40 +00002509 VNC_DEBUG("No password configured on server");
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002510 goto reject;
bellard24236862006-04-30 21:28:36 +00002511 }
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02002512 if (vs->vd->expires < now) {
2513 VNC_DEBUG("Password is expired");
2514 goto reject;
2515 }
bellard24236862006-04-30 21:28:36 +00002516
ths70848512007-08-25 01:37:05 +00002517 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
2518
2519 /* Calculate the expected challenge response */
aliguori753b4052009-02-16 14:59:30 +00002520 pwlen = strlen(vs->vd->password);
ths70848512007-08-25 01:37:05 +00002521 for (i=0; i<sizeof(key); i++)
aliguori753b4052009-02-16 14:59:30 +00002522 key[i] = i<pwlen ? vs->vd->password[i] : 0;
Daniel P. Berrange800567a2015-07-01 18:10:38 +01002523
2524 cipher = qcrypto_cipher_new(
2525 QCRYPTO_CIPHER_ALG_DES_RFB,
2526 QCRYPTO_CIPHER_MODE_ECB,
2527 key, G_N_ELEMENTS(key),
2528 &err);
2529 if (!cipher) {
2530 VNC_DEBUG("Cannot initialize cipher %s",
2531 error_get_pretty(err));
2532 error_free(err);
2533 goto reject;
2534 }
2535
Wolfgang Bumillera1695132015-07-14 14:51:40 +02002536 if (qcrypto_cipher_encrypt(cipher,
Daniel P. Berrange800567a2015-07-01 18:10:38 +01002537 vs->challenge,
2538 response,
2539 VNC_AUTH_CHALLENGE_SIZE,
2540 &err) < 0) {
2541 VNC_DEBUG("Cannot encrypt challenge %s",
2542 error_get_pretty(err));
2543 error_free(err);
2544 goto reject;
2545 }
ths70848512007-08-25 01:37:05 +00002546
2547 /* Compare expected vs actual challenge response */
2548 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
Dong Xu Wange5bed752011-11-22 18:06:24 +08002549 VNC_DEBUG("Client challenge response did not match\n");
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002550 goto reject;
ths70848512007-08-25 01:37:05 +00002551 } else {
aliguori28a76be2009-03-06 20:27:40 +00002552 VNC_DEBUG("Accepting VNC challenge response\n");
2553 vnc_write_u32(vs, 0); /* Accept auth */
2554 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002555
aliguori5fb6c7a2009-03-06 20:27:23 +00002556 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00002557 }
Gonglei60928452015-07-22 17:08:53 +08002558
2559 qcrypto_cipher_free(cipher);
ths70848512007-08-25 01:37:05 +00002560 return 0;
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002561
2562reject:
2563 vnc_write_u32(vs, 1); /* Reject auth */
2564 if (vs->minor >= 8) {
2565 static const char err[] = "Authentication failed";
2566 vnc_write_u32(vs, sizeof(err));
2567 vnc_write(vs, err, sizeof(err));
2568 }
2569 vnc_flush(vs);
2570 vnc_client_error(vs);
Gonglei60928452015-07-22 17:08:53 +08002571 qcrypto_cipher_free(cipher);
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002572 return 0;
ths70848512007-08-25 01:37:05 +00002573}
2574
aliguori5fb6c7a2009-03-06 20:27:23 +00002575void start_auth_vnc(VncState *vs)
ths70848512007-08-25 01:37:05 +00002576{
2577 make_challenge(vs);
2578 /* Send client a 'random' challenge */
2579 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
bellard24236862006-04-30 21:28:36 +00002580 vnc_flush(vs);
2581
ths70848512007-08-25 01:37:05 +00002582 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
ths70848512007-08-25 01:37:05 +00002583}
2584
ths8d5d2d42007-08-25 01:37:51 +00002585
ths60fe76f2007-12-16 03:02:09 +00002586static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002587{
2588 /* We only advertise 1 auth scheme at a time, so client
2589 * must pick the one we sent. Verify this */
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002590 if (data[0] != vs->auth) { /* Reject auth */
aliguori1263b7d2009-03-06 20:27:32 +00002591 VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
ths70848512007-08-25 01:37:05 +00002592 vnc_write_u32(vs, 1);
2593 if (vs->minor >= 8) {
2594 static const char err[] = "Authentication failed";
2595 vnc_write_u32(vs, sizeof(err));
2596 vnc_write(vs, err, sizeof(err));
2597 }
2598 vnc_client_error(vs);
2599 } else { /* Accept requested auth */
2600 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002601 switch (vs->auth) {
ths70848512007-08-25 01:37:05 +00002602 case VNC_AUTH_NONE:
2603 VNC_DEBUG("Accept auth none\n");
balroga26c97a2007-10-31 01:58:56 +00002604 if (vs->minor >= 8) {
2605 vnc_write_u32(vs, 0); /* Accept auth completion */
2606 vnc_flush(vs);
2607 }
aliguori5fb6c7a2009-03-06 20:27:23 +00002608 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00002609 break;
2610
2611 case VNC_AUTH_VNC:
2612 VNC_DEBUG("Start VNC auth\n");
aliguori5fb6c7a2009-03-06 20:27:23 +00002613 start_auth_vnc(vs);
2614 break;
ths70848512007-08-25 01:37:05 +00002615
ths8d5d2d42007-08-25 01:37:51 +00002616 case VNC_AUTH_VENCRYPT:
Dong Xu Wang3a931132011-11-29 16:52:38 +08002617 VNC_DEBUG("Accept VeNCrypt auth\n");
aliguori5fb6c7a2009-03-06 20:27:23 +00002618 start_auth_vencrypt(vs);
2619 break;
ths8d5d2d42007-08-25 01:37:51 +00002620
aliguori2f9606b2009-03-06 20:27:28 +00002621#ifdef CONFIG_VNC_SASL
2622 case VNC_AUTH_SASL:
2623 VNC_DEBUG("Accept SASL auth\n");
2624 start_auth_sasl(vs);
2625 break;
2626#endif /* CONFIG_VNC_SASL */
2627
ths70848512007-08-25 01:37:05 +00002628 default: /* Should not be possible, but just in case */
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002629 VNC_DEBUG("Reject auth %d server code bug\n", vs->auth);
ths70848512007-08-25 01:37:05 +00002630 vnc_write_u8(vs, 1);
2631 if (vs->minor >= 8) {
2632 static const char err[] = "Authentication failed";
2633 vnc_write_u32(vs, sizeof(err));
2634 vnc_write(vs, err, sizeof(err));
2635 }
2636 vnc_client_error(vs);
2637 }
2638 }
2639 return 0;
2640}
2641
ths60fe76f2007-12-16 03:02:09 +00002642static int protocol_version(VncState *vs, uint8_t *version, size_t len)
ths70848512007-08-25 01:37:05 +00002643{
2644 char local[13];
2645
2646 memcpy(local, version, 12);
2647 local[12] = 0;
2648
2649 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
aliguori28a76be2009-03-06 20:27:40 +00002650 VNC_DEBUG("Malformed protocol version %s\n", local);
2651 vnc_client_error(vs);
2652 return 0;
ths70848512007-08-25 01:37:05 +00002653 }
2654 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2655 if (vs->major != 3 ||
aliguori28a76be2009-03-06 20:27:40 +00002656 (vs->minor != 3 &&
2657 vs->minor != 4 &&
2658 vs->minor != 5 &&
2659 vs->minor != 7 &&
2660 vs->minor != 8)) {
2661 VNC_DEBUG("Unsupported client version\n");
2662 vnc_write_u32(vs, VNC_AUTH_INVALID);
2663 vnc_flush(vs);
2664 vnc_client_error(vs);
2665 return 0;
ths70848512007-08-25 01:37:05 +00002666 }
thsb0566f42007-09-30 13:01:15 +00002667 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
ths70848512007-08-25 01:37:05 +00002668 * as equivalent to v3.3 by servers
2669 */
thsb0566f42007-09-30 13:01:15 +00002670 if (vs->minor == 4 || vs->minor == 5)
aliguori28a76be2009-03-06 20:27:40 +00002671 vs->minor = 3;
ths70848512007-08-25 01:37:05 +00002672
2673 if (vs->minor == 3) {
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002674 if (vs->auth == VNC_AUTH_NONE) {
ths70848512007-08-25 01:37:05 +00002675 VNC_DEBUG("Tell client auth none\n");
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002676 vnc_write_u32(vs, vs->auth);
ths70848512007-08-25 01:37:05 +00002677 vnc_flush(vs);
aliguori28a76be2009-03-06 20:27:40 +00002678 start_client_init(vs);
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002679 } else if (vs->auth == VNC_AUTH_VNC) {
ths70848512007-08-25 01:37:05 +00002680 VNC_DEBUG("Tell client VNC auth\n");
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002681 vnc_write_u32(vs, vs->auth);
ths70848512007-08-25 01:37:05 +00002682 vnc_flush(vs);
2683 start_auth_vnc(vs);
2684 } else {
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002685 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
ths70848512007-08-25 01:37:05 +00002686 vnc_write_u32(vs, VNC_AUTH_INVALID);
2687 vnc_flush(vs);
2688 vnc_client_error(vs);
2689 }
2690 } else {
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002691 VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
aliguori28a76be2009-03-06 20:27:40 +00002692 vnc_write_u8(vs, 1); /* num auth */
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002693 vnc_write_u8(vs, vs->auth);
aliguori28a76be2009-03-06 20:27:40 +00002694 vnc_read_when(vs, protocol_client_auth, 1);
2695 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002696 }
bellard24236862006-04-30 21:28:36 +00002697
2698 return 0;
2699}
2700
Corentin Chary999342a2011-02-04 09:05:55 +01002701static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
2702{
2703 struct VncSurface *vs = &vd->guest;
2704
2705 return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
2706}
2707
Corentin Chary7d964c92011-02-04 09:05:56 +01002708void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
2709{
2710 int i, j;
2711
2712 w = (x + w) / VNC_STAT_RECT;
2713 h = (y + h) / VNC_STAT_RECT;
2714 x /= VNC_STAT_RECT;
2715 y /= VNC_STAT_RECT;
2716
Corentin Chary207f3282011-02-04 09:06:03 +01002717 for (j = y; j <= h; j++) {
2718 for (i = x; i <= w; i++) {
Corentin Chary7d964c92011-02-04 09:05:56 +01002719 vs->lossy_rect[j][i] = 1;
2720 }
2721 }
2722}
2723
2724static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
2725{
2726 VncState *vs;
2727 int sty = y / VNC_STAT_RECT;
2728 int stx = x / VNC_STAT_RECT;
2729 int has_dirty = 0;
2730
2731 y = y / VNC_STAT_RECT * VNC_STAT_RECT;
2732 x = x / VNC_STAT_RECT * VNC_STAT_RECT;
2733
2734 QTAILQ_FOREACH(vs, &vd->clients, next) {
Corentin Charybc2429b2011-02-04 09:06:05 +01002735 int j;
Corentin Chary7d964c92011-02-04 09:05:56 +01002736
2737 /* kernel send buffers are full -> refresh later */
2738 if (vs->output.offset) {
2739 continue;
2740 }
2741
2742 if (!vs->lossy_rect[sty][stx]) {
2743 continue;
2744 }
Corentin Chary207f3282011-02-04 09:06:03 +01002745
Corentin Chary7d964c92011-02-04 09:05:56 +01002746 vs->lossy_rect[sty][stx] = 0;
2747 for (j = 0; j < VNC_STAT_RECT; ++j) {
Peter Lievenb4c85dd2014-01-08 10:08:33 +01002748 bitmap_set(vs->dirty[y + j],
2749 x / VNC_DIRTY_PIXELS_PER_BIT,
2750 VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT);
Corentin Chary7d964c92011-02-04 09:05:56 +01002751 }
2752 has_dirty++;
2753 }
Corentin Chary207f3282011-02-04 09:06:03 +01002754
Corentin Chary7d964c92011-02-04 09:05:56 +01002755 return has_dirty;
2756}
2757
2758static int vnc_update_stats(VncDisplay *vd, struct timeval * tv)
Corentin Chary999342a2011-02-04 09:05:55 +01002759{
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002760 int width = pixman_image_get_width(vd->guest.fb);
2761 int height = pixman_image_get_height(vd->guest.fb);
Corentin Chary999342a2011-02-04 09:05:55 +01002762 int x, y;
2763 struct timeval res;
Corentin Chary7d964c92011-02-04 09:05:56 +01002764 int has_dirty = 0;
Corentin Chary999342a2011-02-04 09:05:55 +01002765
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002766 for (y = 0; y < height; y += VNC_STAT_RECT) {
2767 for (x = 0; x < width; x += VNC_STAT_RECT) {
Corentin Chary999342a2011-02-04 09:05:55 +01002768 VncRectStat *rect = vnc_stat_rect(vd, x, y);
2769
2770 rect->updated = false;
2771 }
2772 }
2773
Blue Swirlad620c22011-03-13 10:30:52 +00002774 qemu_timersub(tv, &VNC_REFRESH_STATS, &res);
Corentin Chary999342a2011-02-04 09:05:55 +01002775
2776 if (timercmp(&vd->guest.last_freq_check, &res, >)) {
Corentin Chary7d964c92011-02-04 09:05:56 +01002777 return has_dirty;
Corentin Chary999342a2011-02-04 09:05:55 +01002778 }
2779 vd->guest.last_freq_check = *tv;
2780
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002781 for (y = 0; y < height; y += VNC_STAT_RECT) {
2782 for (x = 0; x < width; x += VNC_STAT_RECT) {
Corentin Chary999342a2011-02-04 09:05:55 +01002783 VncRectStat *rect= vnc_stat_rect(vd, x, y);
2784 int count = ARRAY_SIZE(rect->times);
2785 struct timeval min, max;
2786
2787 if (!timerisset(&rect->times[count - 1])) {
2788 continue ;
2789 }
2790
2791 max = rect->times[(rect->idx + count - 1) % count];
Blue Swirlad620c22011-03-13 10:30:52 +00002792 qemu_timersub(tv, &max, &res);
Corentin Chary999342a2011-02-04 09:05:55 +01002793
2794 if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) {
2795 rect->freq = 0;
Corentin Chary7d964c92011-02-04 09:05:56 +01002796 has_dirty += vnc_refresh_lossy_rect(vd, x, y);
Corentin Chary999342a2011-02-04 09:05:55 +01002797 memset(rect->times, 0, sizeof (rect->times));
2798 continue ;
2799 }
2800
2801 min = rect->times[rect->idx];
2802 max = rect->times[(rect->idx + count - 1) % count];
Blue Swirlad620c22011-03-13 10:30:52 +00002803 qemu_timersub(&max, &min, &res);
Corentin Chary999342a2011-02-04 09:05:55 +01002804
2805 rect->freq = res.tv_sec + res.tv_usec / 1000000.;
2806 rect->freq /= count;
2807 rect->freq = 1. / rect->freq;
2808 }
2809 }
Corentin Chary7d964c92011-02-04 09:05:56 +01002810 return has_dirty;
Corentin Chary999342a2011-02-04 09:05:55 +01002811}
2812
2813double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
2814{
2815 int i, j;
2816 double total = 0;
2817 int num = 0;
2818
2819 x = (x / VNC_STAT_RECT) * VNC_STAT_RECT;
2820 y = (y / VNC_STAT_RECT) * VNC_STAT_RECT;
2821
2822 for (j = y; j <= y + h; j += VNC_STAT_RECT) {
2823 for (i = x; i <= x + w; i += VNC_STAT_RECT) {
2824 total += vnc_stat_rect(vs->vd, i, j)->freq;
2825 num++;
2826 }
2827 }
2828
2829 if (num) {
2830 return total / num;
2831 } else {
2832 return 0;
2833 }
2834}
2835
2836static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
2837{
2838 VncRectStat *rect;
2839
2840 rect = vnc_stat_rect(vd, x, y);
2841 if (rect->updated) {
2842 return ;
2843 }
2844 rect->times[rect->idx] = *tv;
2845 rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times);
2846 rect->updated = true;
2847}
2848
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002849static int vnc_refresh_server_surface(VncDisplay *vd)
2850{
Peter Lievenbea60dd2014-06-30 10:57:51 +02002851 int width = MIN(pixman_image_get_width(vd->guest.fb),
2852 pixman_image_get_width(vd->server));
2853 int height = MIN(pixman_image_get_height(vd->guest.fb),
2854 pixman_image_get_height(vd->server));
Gerd Hoffmanneb8934b2015-08-17 19:56:53 +02002855 int cmp_bytes, server_stride, line_bytes, guest_ll, guest_stride, y = 0;
Peter Lieven12b316d2014-01-08 10:08:35 +01002856 uint8_t *guest_row0 = NULL, *server_row0;
Amit Shah41b4bef2010-02-05 16:34:05 +05302857 VncState *vs;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002858 int has_dirty = 0;
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002859 pixman_image_t *tmpbuf = NULL;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002860
Corentin Chary80e0c8c2011-02-04 09:06:08 +01002861 struct timeval tv = { 0, 0 };
Corentin Chary999342a2011-02-04 09:05:55 +01002862
Corentin Chary80e0c8c2011-02-04 09:06:08 +01002863 if (!vd->non_adaptive) {
2864 gettimeofday(&tv, NULL);
2865 has_dirty = vnc_update_stats(vd, &tv);
2866 }
Corentin Chary999342a2011-02-04 09:05:55 +01002867
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002868 /*
2869 * Walk through the guest dirty map.
2870 * Check and copy modified bits from guest to server surface.
2871 * Update server dirty map.
2872 */
Peter Lievenbea60dd2014-06-30 10:57:51 +02002873 server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
Gerd Hoffmanneb8934b2015-08-17 19:56:53 +02002874 server_stride = guest_stride = guest_ll =
2875 pixman_image_get_stride(vd->server);
Peter Lievenbea60dd2014-06-30 10:57:51 +02002876 cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES,
2877 server_stride);
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002878 if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
2879 int width = pixman_image_get_width(vd->server);
2880 tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
Peter Lieven12b316d2014-01-08 10:08:35 +01002881 } else {
Gerd Hoffmanneb8934b2015-08-17 19:56:53 +02002882 int guest_bpp =
2883 PIXMAN_FORMAT_BPP(pixman_image_get_format(vd->guest.fb));
Peter Lieven12b316d2014-01-08 10:08:35 +01002884 guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
2885 guest_stride = pixman_image_get_stride(vd->guest.fb);
Gerd Hoffmanneb8934b2015-08-17 19:56:53 +02002886 guest_ll = pixman_image_get_width(vd->guest.fb) * ((guest_bpp + 7) / 8);
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002887 }
Gerd Hoffmanneb8934b2015-08-17 19:56:53 +02002888 line_bytes = MIN(server_stride, guest_ll);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002889
Peter Lieven12b316d2014-01-08 10:08:35 +01002890 for (;;) {
2891 int x;
2892 uint8_t *guest_ptr, *server_ptr;
2893 unsigned long offset = find_next_bit((unsigned long *) &vd->guest.dirty,
2894 height * VNC_DIRTY_BPL(&vd->guest),
2895 y * VNC_DIRTY_BPL(&vd->guest));
2896 if (offset == height * VNC_DIRTY_BPL(&vd->guest)) {
2897 /* no more dirty bits */
2898 break;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002899 }
Peter Lieven12b316d2014-01-08 10:08:35 +01002900 y = offset / VNC_DIRTY_BPL(&vd->guest);
2901 x = offset % VNC_DIRTY_BPL(&vd->guest);
2902
2903 server_ptr = server_row0 + y * server_stride + x * cmp_bytes;
2904
2905 if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
2906 qemu_pixman_linebuf_fill(tmpbuf, vd->guest.fb, width, 0, y);
2907 guest_ptr = (uint8_t *)pixman_image_get_data(tmpbuf);
2908 } else {
2909 guest_ptr = guest_row0 + y * guest_stride;
2910 }
2911 guest_ptr += x * cmp_bytes;
2912
2913 for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT);
2914 x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
Peter Lievenbea60dd2014-06-30 10:57:51 +02002915 int _cmp_bytes = cmp_bytes;
Peter Lieven12b316d2014-01-08 10:08:35 +01002916 if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
2917 continue;
2918 }
Gerd Hoffmanneb8934b2015-08-17 19:56:53 +02002919 if ((x + 1) * cmp_bytes > line_bytes) {
2920 _cmp_bytes = line_bytes - x * cmp_bytes;
Peter Lievenbea60dd2014-06-30 10:57:51 +02002921 }
Gerd Hoffmanneb8934b2015-08-17 19:56:53 +02002922 assert(_cmp_bytes >= 0);
Peter Lievenbea60dd2014-06-30 10:57:51 +02002923 if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) {
Peter Lieven12b316d2014-01-08 10:08:35 +01002924 continue;
2925 }
Peter Lievenbea60dd2014-06-30 10:57:51 +02002926 memcpy(server_ptr, guest_ptr, _cmp_bytes);
Peter Lieven12b316d2014-01-08 10:08:35 +01002927 if (!vd->non_adaptive) {
2928 vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
2929 y, &tv);
2930 }
2931 QTAILQ_FOREACH(vs, &vd->clients, next) {
2932 set_bit(x, vs->dirty[y]);
2933 }
2934 has_dirty++;
2935 }
2936
2937 y++;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002938 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002939 qemu_pixman_image_unref(tmpbuf);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002940 return has_dirty;
2941}
2942
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002943static void vnc_refresh(DisplayChangeListener *dcl)
Stefano Stabellini703bc682009-08-03 10:54:05 +01002944{
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002945 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Amit Shah41b4bef2010-02-05 16:34:05 +05302946 VncState *vs, *vn;
2947 int has_dirty, rects = 0;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002948
ChenLiang9d6b2072014-09-29 15:00:40 +08002949 if (QTAILQ_EMPTY(&vd->clients)) {
2950 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX);
2951 return;
2952 }
2953
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +02002954 graphic_hw_update(vd->dcl.con);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002955
Corentin Charybd023f92010-07-07 20:58:02 +02002956 if (vnc_trylock_display(vd)) {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002957 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
Corentin Charybd023f92010-07-07 20:58:02 +02002958 return;
2959 }
2960
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002961 has_dirty = vnc_refresh_server_surface(vd);
Corentin Charybd023f92010-07-07 20:58:02 +02002962 vnc_unlock_display(vd);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002963
Amit Shah41b4bef2010-02-05 16:34:05 +05302964 QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +01002965 rects += vnc_update_client(vs, has_dirty, false);
Stefano Stabellini6185c572010-01-25 12:54:57 +00002966 /* vs might be free()ed here */
Stefano Stabellini703bc682009-08-03 10:54:05 +01002967 }
Corentin Charybd023f92010-07-07 20:58:02 +02002968
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002969 if (has_dirty && rects) {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002970 vd->dcl.update_interval /= 2;
2971 if (vd->dcl.update_interval < VNC_REFRESH_INTERVAL_BASE) {
2972 vd->dcl.update_interval = VNC_REFRESH_INTERVAL_BASE;
2973 }
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002974 } else {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002975 vd->dcl.update_interval += VNC_REFRESH_INTERVAL_INC;
2976 if (vd->dcl.update_interval > VNC_REFRESH_INTERVAL_MAX) {
2977 vd->dcl.update_interval = VNC_REFRESH_INTERVAL_MAX;
2978 }
Stefano Stabellini703bc682009-08-03 10:54:05 +01002979 }
2980}
2981
Michael Tokarev2c8cf542013-06-11 15:42:44 +04002982static void vnc_connect(VncDisplay *vd, int csock,
2983 bool skipauth, bool websocket)
balrog3aa3eea2008-02-03 02:54:04 +00002984{
Markus Armbrusterfedf0d32015-11-03 17:12:03 +01002985 VncState *vs = g_new0(VncState, 1);
Corentin Chary7d964c92011-02-04 09:05:56 +01002986 int i;
2987
aliguori753b4052009-02-16 14:59:30 +00002988 vs->csock = csock;
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +02002989 vs->vd = vd;
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002990
2991 if (skipauth) {
2992 vs->auth = VNC_AUTH_NONE;
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002993 vs->subauth = VNC_AUTH_INVALID;
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002994 } else {
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00002995 if (websocket) {
2996 vs->auth = vd->ws_auth;
2997 vs->subauth = VNC_AUTH_INVALID;
2998 } else {
2999 vs->auth = vd->auth;
3000 vs->subauth = vd->subauth;
3001 }
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01003002 }
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00003003 VNC_DEBUG("Client sock=%d ws=%d auth=%d subauth=%d\n",
3004 csock, websocket, vs->auth, vs->subauth);
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01003005
Anthony Liguori7267c092011-08-20 22:09:37 -05003006 vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
Corentin Chary7d964c92011-02-04 09:05:56 +01003007 for (i = 0; i < VNC_STAT_ROWS; ++i) {
Markus Armbrusterfedf0d32015-11-03 17:12:03 +01003008 vs->lossy_rect[i] = g_new0(uint8_t, VNC_STAT_COLS);
Corentin Chary7d964c92011-02-04 09:05:56 +01003009 }
aliguori753b4052009-02-16 14:59:30 +00003010
3011 VNC_DEBUG("New client on socket %d\n", csock);
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01003012 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
Stefan Hajnoczif9e8cac2013-03-27 10:10:43 +01003013 qemu_set_nonblock(vs->csock);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003014 if (websocket) {
3015 vs->websocket = 1;
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00003016 if (vd->ws_tls) {
Fam Zheng82e1cc42015-06-04 14:45:18 +08003017 qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs);
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003018 } else {
Fam Zheng82e1cc42015-06-04 14:45:18 +08003019 qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs);
Tim Hardeck0057a0d2013-04-23 16:33:01 +02003020 }
Tim Hardeck7536ee42013-01-21 11:04:44 +01003021 } else
Tim Hardeck7536ee42013-01-21 11:04:44 +01003022 {
Fam Zheng82e1cc42015-06-04 14:45:18 +08003023 qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003024 }
aliguori753b4052009-02-16 14:59:30 +00003025
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02003026 vnc_client_cache_addr(vs);
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +02003027 vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED);
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01003028 vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02003029
Daniel P. Berrange8e9b0d22015-07-01 18:10:36 +01003030 if (!vs->websocket) {
Tim Hardeck7536ee42013-01-21 11:04:44 +01003031 vnc_init_state(vs);
3032 }
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +02003033
3034 if (vd->num_connecting > vd->connections_limit) {
3035 QTAILQ_FOREACH(vs, &vd->clients, next) {
3036 if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) {
3037 vnc_disconnect_start(vs);
3038 return;
3039 }
3040 }
3041 }
Tim Hardeck7536ee42013-01-21 11:04:44 +01003042}
3043
3044void vnc_init_state(VncState *vs)
3045{
Tim Hardeck6fd8e792013-01-21 11:04:45 +01003046 vs->initialized = true;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003047 VncDisplay *vd = vs->vd;
3048
aliguori753b4052009-02-16 14:59:30 +00003049 vs->last_x = -1;
3050 vs->last_y = -1;
3051
3052 vs->as.freq = 44100;
3053 vs->as.nchannels = 2;
3054 vs->as.fmt = AUD_FMT_S16;
3055 vs->as.endianness = 0;
3056
Corentin Charybd023f92010-07-07 20:58:02 +02003057 qemu_mutex_init(&vs->output_mutex);
Corentin Chary175b2a62012-03-14 07:58:47 +01003058 vs->bh = qemu_bh_new(vnc_jobs_bh, vs);
Corentin Charybd023f92010-07-07 20:58:02 +02003059
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +02003060 QTAILQ_INSERT_TAIL(&vd->clients, vs, next);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01003061
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +02003062 graphic_hw_update(vd->dcl.con);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01003063
balrog3aa3eea2008-02-03 02:54:04 +00003064 vnc_write(vs, "RFB 003.008\n", 12);
3065 vnc_flush(vs);
3066 vnc_read_when(vs, protocol_version, 12);
malc53762dd2008-12-01 20:57:52 +00003067 reset_keys(vs);
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01003068 if (vs->vd->lock_key_sync)
3069 vs->led = qemu_add_led_event_handler(kbd_leds, vs);
aliguori753b4052009-02-16 14:59:30 +00003070
Anthony Liguori37c34d92010-03-10 09:38:29 -06003071 vs->mouse_mode_notifier.notify = check_pointer_type_change;
3072 qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
3073
Gerd Hoffmann198a0032009-06-16 14:19:48 +02003074 /* vs might be free()ed here */
balrog3aa3eea2008-02-03 02:54:04 +00003075}
3076
Tim Hardeck7536ee42013-01-21 11:04:44 +01003077static void vnc_listen_read(void *opaque, bool websocket)
bellard24236862006-04-30 21:28:36 +00003078{
aliguori753b4052009-02-16 14:59:30 +00003079 VncDisplay *vs = opaque;
bellard24236862006-04-30 21:28:36 +00003080 struct sockaddr_in addr;
3081 socklen_t addrlen = sizeof(addr);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003082 int csock;
bellard24236862006-04-30 21:28:36 +00003083
balrog9f60ad52008-01-14 21:45:55 +00003084 /* Catch-up */
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +02003085 graphic_hw_update(vs->dcl.con);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003086 if (websocket) {
3087 csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen);
Daniel P. Berrange8e9b0d22015-07-01 18:10:36 +01003088 } else {
Tim Hardeck7536ee42013-01-21 11:04:44 +01003089 csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
3090 }
balrog9f60ad52008-01-14 21:45:55 +00003091
aliguori753b4052009-02-16 14:59:30 +00003092 if (csock != -1) {
Peter Lieven86152432014-09-05 22:07:41 +02003093 socket_set_nodelay(csock);
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003094 vnc_connect(vs, csock, false, websocket);
bellard24236862006-04-30 21:28:36 +00003095 }
3096}
3097
Tim Hardeck7536ee42013-01-21 11:04:44 +01003098static void vnc_listen_regular_read(void *opaque)
3099{
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003100 vnc_listen_read(opaque, false);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003101}
3102
Tim Hardeck7536ee42013-01-21 11:04:44 +01003103static void vnc_listen_websocket_read(void *opaque)
3104{
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003105 vnc_listen_read(opaque, true);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003106}
Tim Hardeck7536ee42013-01-21 11:04:44 +01003107
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01003108static const DisplayChangeListenerOps dcl_ops = {
Benjamin Herrenschmidt34da30a2014-07-07 17:18:19 +10003109 .dpy_name = "vnc",
3110 .dpy_refresh = vnc_refresh,
3111 .dpy_gfx_copy = vnc_dpy_copy,
3112 .dpy_gfx_update = vnc_dpy_update,
3113 .dpy_gfx_switch = vnc_dpy_switch,
3114 .dpy_gfx_check_format = qemu_pixman_check_format,
3115 .dpy_mouse_set = vnc_mouse_set,
3116 .dpy_cursor_define = vnc_dpy_cursor_define,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01003117};
3118
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003119void vnc_display_init(const char *id)
bellard24236862006-04-30 21:28:36 +00003120{
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003121 VncDisplay *vs;
3122
3123 if (vnc_display_find(id) != NULL) {
3124 return;
3125 }
3126 vs = g_malloc0(sizeof(*vs));
bellard24236862006-04-30 21:28:36 +00003127
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003128 vs->id = strdup(id);
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +02003129 QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
bellard24236862006-04-30 21:28:36 +00003130
3131 vs->lsock = -1;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003132 vs->lwebsock = -1;
bellard24236862006-04-30 21:28:36 +00003133
Amit Shah41b4bef2010-02-05 16:34:05 +05303134 QTAILQ_INIT(&vs->clients);
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003135 vs->expires = TIME_MAX;
bellard24236862006-04-30 21:28:36 +00003136
Gerd Hoffmann40066172014-05-21 13:18:20 +02003137 if (keyboard_layout) {
3138 trace_vnc_key_map_init(keyboard_layout);
aliguori04837552009-03-06 20:27:10 +00003139 vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
Gerd Hoffmann40066172014-05-21 13:18:20 +02003140 } else {
aliguori04837552009-03-06 20:27:10 +00003141 vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
Gerd Hoffmann40066172014-05-21 13:18:20 +02003142 }
bellard24236862006-04-30 21:28:36 +00003143
bellard24236862006-04-30 21:28:36 +00003144 if (!vs->kbd_layout)
aliguori28a76be2009-03-06 20:27:40 +00003145 exit(1);
bellard24236862006-04-30 21:28:36 +00003146
Corentin Charybd023f92010-07-07 20:58:02 +02003147 qemu_mutex_init(&vs->mutex);
3148 vnc_start_worker_thread();
Corentin Charybd023f92010-07-07 20:58:02 +02003149
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003150 vs->dcl.ops = &dcl_ops;
Gerd Hoffmann52090892013-04-23 15:44:31 +02003151 register_displaychangelistener(&vs->dcl);
ths71cab5c2007-08-25 01:35:38 +00003152}
ths73fc9742006-12-22 02:09:07 +00003153
ths6f430242007-08-25 01:39:57 +00003154
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003155static void vnc_display_close(VncDisplay *vs)
ths71cab5c2007-08-25 01:35:38 +00003156{
aliguori452b4d82009-02-11 21:00:38 +00003157 if (!vs)
3158 return;
Gerd Hoffmannbf7aa452015-02-19 10:46:49 +01003159 vs->enabled = false;
3160 vs->is_unix = false;
ths71cab5c2007-08-25 01:35:38 +00003161 if (vs->lsock != -1) {
Fam Zheng82e1cc42015-06-04 14:45:18 +08003162 qemu_set_fd_handler(vs->lsock, NULL, NULL, NULL);
aliguori28a76be2009-03-06 20:27:40 +00003163 close(vs->lsock);
3164 vs->lsock = -1;
ths71cab5c2007-08-25 01:35:38 +00003165 }
Gerd Hoffmannbf7aa452015-02-19 10:46:49 +01003166 vs->ws_enabled = false;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003167 if (vs->lwebsock != -1) {
Fam Zheng82e1cc42015-06-04 14:45:18 +08003168 qemu_set_fd_handler(vs->lwebsock, NULL, NULL, NULL);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003169 close(vs->lwebsock);
3170 vs->lwebsock = -1;
3171 }
ths70848512007-08-25 01:37:05 +00003172 vs->auth = VNC_AUTH_INVALID;
ths8d5d2d42007-08-25 01:37:51 +00003173 vs->subauth = VNC_AUTH_INVALID;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003174 if (vs->tlscreds) {
3175 object_unparent(OBJECT(vs->tlscreds));
3176 }
3177 g_free(vs->tlsaclname);
3178 vs->tlsaclname = NULL;
ths71cab5c2007-08-25 01:35:38 +00003179}
3180
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003181int vnc_display_password(const char *id, const char *password)
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003182{
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003183 VncDisplay *vs = vnc_display_find(id);
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003184
3185 if (!vs) {
Luiz Capitulinoa6aa9d32011-12-07 10:19:10 -02003186 return -EINVAL;
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003187 }
Gerd Hoffmanncf864562013-12-11 13:15:37 +01003188 if (vs->auth == VNC_AUTH_NONE) {
3189 error_printf_unless_qmp("If you want use passwords please enable "
3190 "password auth using '-vnc ${dpy},password'.");
3191 return -EINVAL;
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003192 }
3193
Markus Armbruster64641d82014-06-06 18:47:43 +02003194 g_free(vs->password);
Markus Armbrusterc14e9842014-06-06 18:47:44 +02003195 vs->password = g_strdup(password);
Luiz Capitulinoa6aa9d32011-12-07 10:19:10 -02003196
3197 return 0;
ths70848512007-08-25 01:37:05 +00003198}
3199
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003200int vnc_display_pw_expire(const char *id, time_t expires)
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003201{
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003202 VncDisplay *vs = vnc_display_find(id);
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003203
Gerd Hoffmann1643f2b2012-05-24 10:55:01 +02003204 if (!vs) {
3205 return -EINVAL;
3206 }
3207
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003208 vs->expires = expires;
3209 return 0;
3210}
3211
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003212char *vnc_display_local_addr(const char *id)
Anthony Liguorif92f8af2009-05-20 13:01:02 -05003213{
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003214 VncDisplay *vs = vnc_display_find(id);
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +02003215
Gerd Hoffmann9e0ff752015-02-11 17:33:33 +01003216 assert(vs);
Anthony Liguorif92f8af2009-05-20 13:01:02 -05003217 return vnc_socket_local_addr("%s:%s", vs->lsock);
3218}
3219
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003220static QemuOptsList qemu_vnc_opts = {
3221 .name = "vnc",
3222 .head = QTAILQ_HEAD_INITIALIZER(qemu_vnc_opts.head),
3223 .implied_opt_name = "vnc",
3224 .desc = {
3225 {
3226 .name = "vnc",
3227 .type = QEMU_OPT_STRING,
3228 },{
3229 .name = "websocket",
3230 .type = QEMU_OPT_STRING,
3231 },{
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003232 .name = "tls-creds",
3233 .type = QEMU_OPT_STRING,
3234 },{
3235 /* Deprecated in favour of tls-creds */
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003236 .name = "x509",
3237 .type = QEMU_OPT_STRING,
3238 },{
3239 .name = "share",
3240 .type = QEMU_OPT_STRING,
3241 },{
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +02003242 .name = "display",
3243 .type = QEMU_OPT_STRING,
3244 },{
3245 .name = "head",
3246 .type = QEMU_OPT_NUMBER,
3247 },{
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +02003248 .name = "connections",
3249 .type = QEMU_OPT_NUMBER,
3250 },{
Gonglei88428b72015-01-30 10:14:34 +08003251 .name = "to",
3252 .type = QEMU_OPT_NUMBER,
3253 },{
3254 .name = "ipv4",
3255 .type = QEMU_OPT_BOOL,
3256 },{
3257 .name = "ipv6",
3258 .type = QEMU_OPT_BOOL,
3259 },{
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003260 .name = "password",
3261 .type = QEMU_OPT_BOOL,
3262 },{
3263 .name = "reverse",
3264 .type = QEMU_OPT_BOOL,
3265 },{
3266 .name = "lock-key-sync",
3267 .type = QEMU_OPT_BOOL,
3268 },{
3269 .name = "sasl",
3270 .type = QEMU_OPT_BOOL,
3271 },{
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003272 /* Deprecated in favour of tls-creds */
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003273 .name = "tls",
3274 .type = QEMU_OPT_BOOL,
3275 },{
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003276 /* Deprecated in favour of tls-creds */
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003277 .name = "x509verify",
Daniel P. Berrange8c7d0642015-03-10 16:27:34 +00003278 .type = QEMU_OPT_STRING,
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003279 },{
3280 .name = "acl",
3281 .type = QEMU_OPT_BOOL,
3282 },{
3283 .name = "lossy",
3284 .type = QEMU_OPT_BOOL,
3285 },{
3286 .name = "non-adaptive",
3287 .type = QEMU_OPT_BOOL,
3288 },
3289 { /* end of list */ }
3290 },
3291};
3292
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003293
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003294static int
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003295vnc_display_setup_auth(VncDisplay *vs,
3296 bool password,
3297 bool sasl,
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003298 bool websocket,
3299 Error **errp)
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003300{
3301 /*
3302 * We have a choice of 3 authentication options
3303 *
3304 * 1. none
3305 * 2. vnc
3306 * 3. sasl
3307 *
3308 * The channel can be run in 2 modes
3309 *
3310 * 1. clear
3311 * 2. tls
3312 *
3313 * And TLS can use 2 types of credentials
3314 *
3315 * 1. anon
3316 * 2. x509
3317 *
3318 * We thus have 9 possible logical combinations
3319 *
3320 * 1. clear + none
3321 * 2. clear + vnc
3322 * 3. clear + sasl
3323 * 4. tls + anon + none
3324 * 5. tls + anon + vnc
3325 * 6. tls + anon + sasl
3326 * 7. tls + x509 + none
3327 * 8. tls + x509 + vnc
3328 * 9. tls + x509 + sasl
3329 *
3330 * These need to be mapped into the VNC auth schemes
3331 * in an appropriate manner. In regular VNC, all the
3332 * TLS options get mapped into VNC_AUTH_VENCRYPT
3333 * sub-auth types.
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00003334 *
3335 * In websockets, the https:// protocol already provides
3336 * TLS support, so there is no need to make use of the
3337 * VeNCrypt extension. Furthermore, websockets browser
3338 * clients could not use VeNCrypt even if they wanted to,
3339 * as they cannot control when the TLS handshake takes
3340 * place. Thus there is no option but to rely on https://,
3341 * meaning combinations 4->6 and 7->9 will be mapped to
3342 * VNC auth schemes in the same way as combos 1->3.
3343 *
3344 * Regardless of fact that we have a different mapping to
3345 * VNC auth mechs for plain VNC vs websockets VNC, the end
3346 * result has the same security characteristics.
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003347 */
3348 if (password) {
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003349 if (vs->tlscreds) {
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003350 vs->auth = VNC_AUTH_VENCRYPT;
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00003351 if (websocket) {
3352 vs->ws_tls = true;
3353 }
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003354 if (object_dynamic_cast(OBJECT(vs->tlscreds),
3355 TYPE_QCRYPTO_TLS_CREDS_X509)) {
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003356 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
3357 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003358 } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
3359 TYPE_QCRYPTO_TLS_CREDS_ANON)) {
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003360 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
3361 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003362 } else {
3363 error_setg(errp,
3364 "Unsupported TLS cred type %s",
3365 object_get_typename(OBJECT(vs->tlscreds)));
3366 return -1;
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003367 }
3368 } else {
3369 VNC_DEBUG("Initializing VNC server with password auth\n");
3370 vs->auth = VNC_AUTH_VNC;
3371 vs->subauth = VNC_AUTH_INVALID;
3372 }
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00003373 if (websocket) {
3374 vs->ws_auth = VNC_AUTH_VNC;
3375 } else {
3376 vs->ws_auth = VNC_AUTH_INVALID;
3377 }
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003378 } else if (sasl) {
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003379 if (vs->tlscreds) {
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003380 vs->auth = VNC_AUTH_VENCRYPT;
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00003381 if (websocket) {
3382 vs->ws_tls = true;
3383 }
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003384 if (object_dynamic_cast(OBJECT(vs->tlscreds),
3385 TYPE_QCRYPTO_TLS_CREDS_X509)) {
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003386 VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
3387 vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003388 } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
3389 TYPE_QCRYPTO_TLS_CREDS_ANON)) {
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003390 VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
3391 vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003392 } else {
3393 error_setg(errp,
3394 "Unsupported TLS cred type %s",
3395 object_get_typename(OBJECT(vs->tlscreds)));
3396 return -1;
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003397 }
3398 } else {
3399 VNC_DEBUG("Initializing VNC server with SASL auth\n");
3400 vs->auth = VNC_AUTH_SASL;
3401 vs->subauth = VNC_AUTH_INVALID;
3402 }
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00003403 if (websocket) {
3404 vs->ws_auth = VNC_AUTH_SASL;
3405 } else {
3406 vs->ws_auth = VNC_AUTH_INVALID;
3407 }
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003408 } else {
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003409 if (vs->tlscreds) {
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003410 vs->auth = VNC_AUTH_VENCRYPT;
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00003411 if (websocket) {
3412 vs->ws_tls = true;
3413 }
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003414 if (object_dynamic_cast(OBJECT(vs->tlscreds),
3415 TYPE_QCRYPTO_TLS_CREDS_X509)) {
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003416 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
3417 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003418 } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
3419 TYPE_QCRYPTO_TLS_CREDS_ANON)) {
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003420 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
3421 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003422 } else {
3423 error_setg(errp,
3424 "Unsupported TLS cred type %s",
3425 object_get_typename(OBJECT(vs->tlscreds)));
3426 return -1;
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003427 }
3428 } else {
3429 VNC_DEBUG("Initializing VNC server with no auth\n");
3430 vs->auth = VNC_AUTH_NONE;
3431 vs->subauth = VNC_AUTH_INVALID;
3432 }
Daniel P. Berrangef9148c82015-03-17 13:42:57 +00003433 if (websocket) {
3434 vs->ws_auth = VNC_AUTH_NONE;
3435 } else {
3436 vs->ws_auth = VNC_AUTH_INVALID;
3437 }
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003438 }
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003439 return 0;
Daniel P. Berrange0dd72e12015-03-17 13:42:56 +00003440}
3441
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003442
3443/*
3444 * Handle back compat with old CLI syntax by creating some
3445 * suitable QCryptoTLSCreds objects
3446 */
3447static QCryptoTLSCreds *
3448vnc_display_create_creds(bool x509,
3449 bool x509verify,
3450 const char *dir,
3451 const char *id,
3452 Error **errp)
3453{
3454 gchar *credsid = g_strdup_printf("tlsvnc%s", id);
3455 Object *parent = object_get_objects_root();
3456 Object *creds;
3457 Error *err = NULL;
3458
3459 if (x509) {
3460 creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_X509,
3461 parent,
3462 credsid,
3463 &err,
3464 "endpoint", "server",
3465 "dir", dir,
3466 "verify-peer", x509verify ? "yes" : "no",
3467 NULL);
3468 } else {
3469 creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON,
3470 parent,
3471 credsid,
3472 &err,
3473 "endpoint", "server",
3474 NULL);
3475 }
3476
3477 g_free(credsid);
3478
3479 if (err) {
3480 error_propagate(errp, err);
3481 return NULL;
3482 }
3483
3484 return QCRYPTO_TLS_CREDS(creds);
3485}
3486
3487
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003488void vnc_display_open(const char *id, Error **errp)
ths71cab5c2007-08-25 01:35:38 +00003489{
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003490 VncDisplay *vs = vnc_display_find(id);
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003491 QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003492 SocketAddress *saddr = NULL, *wsaddr = NULL;
Gongleie2a11d92015-01-30 10:14:35 +08003493 const char *share, *device_id;
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +02003494 QemuConsole *con;
Gongleia2c72de2015-01-30 10:14:36 +08003495 bool password = false;
3496 bool reverse = false;
Gongleie2a11d92015-01-30 10:14:35 +08003497 const char *vnc;
Gerd Hoffmanne5560322015-02-19 11:31:44 +01003498 char *h;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003499 const char *credid;
Gongleia2c72de2015-01-30 10:14:36 +08003500 bool sasl = false;
Daniel P. Berranged169f042015-03-17 13:42:55 +00003501#ifdef CONFIG_VNC_SASL
aliguori2f9606b2009-03-06 20:27:28 +00003502 int saslErr;
3503#endif
aliguori76655d62009-03-06 20:27:37 +00003504 int acl = 0;
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01003505 int lock_key_sync = 1;
ths71cab5c2007-08-25 01:35:38 +00003506
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +02003507 if (!vs) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003508 error_setg(errp, "VNC display not active");
3509 return;
3510 }
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003511 vnc_display_close(vs);
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003512
3513 if (!opts) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003514 return;
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003515 }
Gongleie2a11d92015-01-30 10:14:35 +08003516 vnc = qemu_opt_get(opts, "vnc");
3517 if (!vnc || strcmp(vnc, "none") == 0) {
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003518 return;
3519 }
Gongleie2a11d92015-01-30 10:14:35 +08003520
Gerd Hoffmanne5560322015-02-19 11:31:44 +01003521 h = strrchr(vnc, ':');
3522 if (h) {
Ján Tomko274c3b52015-04-27 17:03:14 +02003523 size_t hlen = h - vnc;
3524
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003525 const char *websocket = qemu_opt_get(opts, "websocket");
3526 int to = qemu_opt_get_number(opts, "to", 0);
3527 bool has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
3528 bool has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
3529
3530 saddr = g_new0(SocketAddress, 1);
3531 if (websocket) {
3532 if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
3533 error_setg(errp,
3534 "SHA1 hash support is required for websockets");
3535 goto fail;
3536 }
3537
3538 wsaddr = g_new0(SocketAddress, 1);
3539 vs->ws_enabled = true;
Ján Tomko274c3b52015-04-27 17:03:14 +02003540 }
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003541
3542 if (strncmp(vnc, "unix:", 5) == 0) {
Eric Blake2d32add2015-10-26 16:34:55 -06003543 saddr->type = SOCKET_ADDRESS_KIND_UNIX;
3544 saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
3545 saddr->u.q_unix->path = g_strdup(vnc + 5);
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003546
3547 if (vs->ws_enabled) {
3548 error_setg(errp, "UNIX sockets not supported with websock");
3549 goto fail;
3550 }
3551 } else {
3552 unsigned long long baseport;
Eric Blake2d32add2015-10-26 16:34:55 -06003553 saddr->type = SOCKET_ADDRESS_KIND_INET;
3554 saddr->u.inet = g_new0(InetSocketAddress, 1);
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003555 if (vnc[0] == '[' && vnc[hlen - 1] == ']') {
Eric Blake2d32add2015-10-26 16:34:55 -06003556 saddr->u.inet->host = g_strndup(vnc + 1, hlen - 2);
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003557 } else {
Eric Blake2d32add2015-10-26 16:34:55 -06003558 saddr->u.inet->host = g_strndup(vnc, hlen);
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003559 }
3560 if (parse_uint_full(h + 1, &baseport, 10) < 0) {
3561 error_setg(errp, "can't convert to a number: %s", h + 1);
3562 goto fail;
3563 }
3564 if (baseport > 65535 ||
3565 baseport + 5900 > 65535) {
3566 error_setg(errp, "port %s out of range", h + 1);
3567 goto fail;
3568 }
Eric Blake2d32add2015-10-26 16:34:55 -06003569 saddr->u.inet->port = g_strdup_printf(
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003570 "%d", (int)baseport + 5900);
3571
3572 if (to) {
Eric Blake2d32add2015-10-26 16:34:55 -06003573 saddr->u.inet->has_to = true;
3574 saddr->u.inet->to = to;
Yang Hongyang4d77b1f2015-10-27 14:10:52 +08003575 saddr->u.inet->has_to = true;
3576 saddr->u.inet->to = to + 5900;
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003577 }
Eric Blake2d32add2015-10-26 16:34:55 -06003578 saddr->u.inet->ipv4 = saddr->u.inet->has_ipv4 = has_ipv4;
3579 saddr->u.inet->ipv6 = saddr->u.inet->has_ipv6 = has_ipv6;
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003580
3581 if (vs->ws_enabled) {
Eric Blake2d32add2015-10-26 16:34:55 -06003582 wsaddr->type = SOCKET_ADDRESS_KIND_INET;
3583 wsaddr->u.inet = g_new0(InetSocketAddress, 1);
3584 wsaddr->u.inet->host = g_strdup(saddr->u.inet->host);
3585 wsaddr->u.inet->port = g_strdup(websocket);
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003586
3587 if (to) {
Eric Blake2d32add2015-10-26 16:34:55 -06003588 wsaddr->u.inet->has_to = true;
3589 wsaddr->u.inet->to = to;
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003590 }
Eric Blake2d32add2015-10-26 16:34:55 -06003591 wsaddr->u.inet->ipv4 = wsaddr->u.inet->has_ipv4 = has_ipv4;
3592 wsaddr->u.inet->ipv6 = wsaddr->u.inet->has_ipv6 = has_ipv6;
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003593 }
3594 }
Gerd Hoffmanne5560322015-02-19 11:31:44 +01003595 } else {
3596 error_setg(errp, "no vnc port specified");
3597 goto fail;
Gongleie2a11d92015-01-30 10:14:35 +08003598 }
Gerd Hoffmanne5560322015-02-19 11:31:44 +01003599
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003600 password = qemu_opt_get_bool(opts, "password", false);
Daniel P. Berrange800567a2015-07-01 18:10:38 +01003601 if (password) {
3602 if (fips_get_state()) {
3603 error_setg(errp,
3604 "VNC password auth disabled due to FIPS mode, "
3605 "consider using the VeNCrypt or SASL authentication "
3606 "methods as an alternative");
3607 goto fail;
3608 }
3609 if (!qcrypto_cipher_supports(
3610 QCRYPTO_CIPHER_ALG_DES_RFB)) {
3611 error_setg(errp,
3612 "Cipher backend does not support DES RFB algorithm");
3613 goto fail;
3614 }
ths70848512007-08-25 01:37:05 +00003615 }
3616
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003617 reverse = qemu_opt_get_bool(opts, "reverse", false);
3618 lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true);
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003619 sasl = qemu_opt_get_bool(opts, "sasl", false);
Daniel P. Berranged169f042015-03-17 13:42:55 +00003620#ifndef CONFIG_VNC_SASL
3621 if (sasl) {
3622 error_setg(errp, "VNC SASL auth requires cyrus-sasl support");
3623 goto fail;
3624 }
3625#endif /* CONFIG_VNC_SASL */
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003626 credid = qemu_opt_get(opts, "tls-creds");
3627 if (credid) {
3628 Object *creds;
3629 if (qemu_opt_get(opts, "tls") ||
3630 qemu_opt_get(opts, "x509") ||
3631 qemu_opt_get(opts, "x509verify")) {
3632 error_setg(errp,
3633 "'credid' parameter is mutually exclusive with "
3634 "'tls', 'x509' and 'x509verify' parameters");
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003635 goto fail;
3636 }
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003637
3638 creds = object_resolve_path_component(
3639 object_get_objects_root(), credid);
3640 if (!creds) {
3641 error_setg(errp, "No TLS credentials with id '%s'",
3642 credid);
3643 goto fail;
3644 }
3645 vs->tlscreds = (QCryptoTLSCreds *)
3646 object_dynamic_cast(creds,
3647 TYPE_QCRYPTO_TLS_CREDS);
3648 if (!vs->tlscreds) {
3649 error_setg(errp, "Object with id '%s' is not TLS credentials",
3650 credid);
3651 goto fail;
3652 }
3653 object_ref(OBJECT(vs->tlscreds));
3654
3655 if (vs->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
3656 error_setg(errp,
3657 "Expecting TLS credentials with a server endpoint");
3658 goto fail;
3659 }
3660 } else {
3661 const char *path;
3662 bool tls = false, x509 = false, x509verify = false;
3663 tls = qemu_opt_get_bool(opts, "tls", false);
3664 if (tls) {
3665 path = qemu_opt_get(opts, "x509");
3666
3667 if (path) {
3668 x509 = true;
3669 } else {
3670 path = qemu_opt_get(opts, "x509verify");
3671 if (path) {
3672 x509 = true;
3673 x509verify = true;
3674 }
3675 }
3676 vs->tlscreds = vnc_display_create_creds(x509,
3677 x509verify,
3678 path,
3679 vs->id,
3680 errp);
3681 if (!vs->tlscreds) {
3682 goto fail;
3683 }
3684 }
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003685 }
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003686 acl = qemu_opt_get_bool(opts, "acl", false);
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003687
3688 share = qemu_opt_get(opts, "share");
3689 if (share) {
3690 if (strcmp(share, "ignore") == 0) {
3691 vs->share_policy = VNC_SHARE_POLICY_IGNORE;
3692 } else if (strcmp(share, "allow-exclusive") == 0) {
3693 vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
3694 } else if (strcmp(share, "force-shared") == 0) {
3695 vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
3696 } else {
3697 error_setg(errp, "unknown vnc share= option");
3698 goto fail;
3699 }
3700 } else {
3701 vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
3702 }
Gerd Hoffmanne5f34cd2014-10-02 12:09:34 +02003703 vs->connections_limit = qemu_opt_get_number(opts, "connections", 32);
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003704
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003705#ifdef CONFIG_VNC_JPEG
3706 vs->lossy = qemu_opt_get_bool(opts, "lossy", false);
3707#endif
3708 vs->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false);
Peter Lievene22492d2014-01-08 10:08:38 +01003709 /* adaptive updates are only used with tight encoding and
3710 * if lossy updates are enabled so we can disable all the
3711 * calculations otherwise */
3712 if (!vs->lossy) {
3713 vs->non_adaptive = true;
3714 }
3715
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003716 if (acl) {
Gerd Hoffmannc8496402014-10-21 14:50:42 +02003717 if (strcmp(vs->id, "default") == 0) {
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003718 vs->tlsaclname = g_strdup("vnc.x509dname");
Gerd Hoffmannc8496402014-10-21 14:50:42 +02003719 } else {
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003720 vs->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vs->id);
Gerd Hoffmannc8496402014-10-21 14:50:42 +02003721 }
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003722 qemu_acl_init(vs->tlsaclname);
3723 }
aliguori76655d62009-03-06 20:27:37 +00003724#ifdef CONFIG_VNC_SASL
3725 if (acl && sasl) {
Gerd Hoffmannc8496402014-10-21 14:50:42 +02003726 char *aclname;
3727
3728 if (strcmp(vs->id, "default") == 0) {
3729 aclname = g_strdup("vnc.username");
3730 } else {
3731 aclname = g_strdup_printf("vnc.%s.username", vs->id);
3732 }
3733 vs->sasl.acl = qemu_acl_init(aclname);
Gerd Hoffmannc8496402014-10-21 14:50:42 +02003734 g_free(aclname);
aliguori76655d62009-03-06 20:27:37 +00003735 }
3736#endif
3737
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003738 if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) {
Daniel P. Berrange3e305e42015-08-06 14:39:32 +01003739 goto fail;
3740 }
bellard24236862006-04-30 21:28:36 +00003741
aliguori2f9606b2009-03-06 20:27:28 +00003742#ifdef CONFIG_VNC_SASL
3743 if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003744 error_setg(errp, "Failed to initialize SASL auth: %s",
3745 sasl_errstring(saslErr, NULL, NULL));
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003746 goto fail;
aliguori2f9606b2009-03-06 20:27:28 +00003747 }
3748#endif
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01003749 vs->lock_key_sync = lock_key_sync;
aliguori2f9606b2009-03-06 20:27:28 +00003750
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +02003751 device_id = qemu_opt_get(opts, "display");
3752 if (device_id) {
3753 DeviceState *dev;
3754 int head = qemu_opt_get_number(opts, "head", 0);
3755
3756 dev = qdev_find_recursive(sysbus_get_default(), device_id);
3757 if (dev == NULL) {
Markus Armbrusterf3cf80e2015-03-13 18:43:09 +01003758 error_setg(errp, "Device '%s' not found", device_id);
Gerd Hoffmann1d0d59f2014-09-18 12:54:49 +02003759 goto fail;
3760 }
3761
3762 con = qemu_console_lookup_by_device(dev, head);
3763 if (con == NULL) {
3764 error_setg(errp, "Device %s is not bound to a QemuConsole",
3765 device_id);
3766 goto fail;
3767 }
3768 } else {
3769 con = NULL;
3770 }
3771
3772 if (con != vs->dcl.con) {
3773 unregister_displaychangelistener(&vs->dcl);
3774 vs->dcl.con = con;
3775 register_displaychangelistener(&vs->dcl);
3776 }
3777
balrog3aa3eea2008-02-03 02:54:04 +00003778 if (reverse) {
aliguori9712eca2008-11-11 20:51:59 +00003779 /* connect to viewer */
Paolo Bonzini007fcd3e2012-10-18 09:01:01 +02003780 int csock;
3781 vs->lsock = -1;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003782 vs->lwebsock = -1;
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003783 if (vs->ws_enabled) {
3784 error_setg(errp, "Cannot use websockets in reverse mode");
3785 goto fail;
balrog3aa3eea2008-02-03 02:54:04 +00003786 }
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003787 csock = socket_connect(saddr, errp, NULL, NULL);
Paolo Bonzini007fcd3e2012-10-18 09:01:01 +02003788 if (csock < 0) {
3789 goto fail;
3790 }
Eric Blake2d32add2015-10-26 16:34:55 -06003791 vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003792 vnc_connect(vs, csock, false, false);
aliguori9712eca2008-11-11 20:51:59 +00003793 } else {
3794 /* listen for connects */
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003795 vs->lsock = socket_listen(saddr, errp);
3796 if (vs->lsock < 0) {
3797 goto fail;
3798 }
Eric Blake2d32add2015-10-26 16:34:55 -06003799 vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003800 if (vs->ws_enabled) {
3801 vs->lwebsock = socket_listen(wsaddr, errp);
3802 if (vs->lwebsock < 0) {
3803 if (vs->lsock != -1) {
3804 close(vs->lsock);
3805 vs->lsock = -1;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003806 }
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003807 goto fail;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003808 }
aliguori9712eca2008-11-11 20:51:59 +00003809 }
Gerd Hoffmannbf7aa452015-02-19 10:46:49 +01003810 vs->enabled = true;
Fam Zheng82e1cc42015-06-04 14:45:18 +08003811 qemu_set_fd_handler(vs->lsock, vnc_listen_regular_read, NULL, vs);
Gerd Hoffmannbf7aa452015-02-19 10:46:49 +01003812 if (vs->ws_enabled) {
Fam Zheng82e1cc42015-06-04 14:45:18 +08003813 qemu_set_fd_handler(vs->lwebsock, vnc_listen_websocket_read,
3814 NULL, vs);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003815 }
bellard24236862006-04-30 21:28:36 +00003816 }
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003817
3818 qapi_free_SocketAddress(saddr);
3819 qapi_free_SocketAddress(wsaddr);
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003820 return;
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003821
3822fail:
Daniel P. Berrangee0d03b82015-08-14 18:56:44 +01003823 qapi_free_SocketAddress(saddr);
3824 qapi_free_SocketAddress(wsaddr);
Gerd Hoffmannbf7aa452015-02-19 10:46:49 +01003825 vs->enabled = false;
Gerd Hoffmannbf7aa452015-02-19 10:46:49 +01003826 vs->ws_enabled = false;
bellard24236862006-04-30 21:28:36 +00003827}
Daniel P. Berrange13661082011-06-23 13:31:42 +01003828
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003829void vnc_display_add_client(const char *id, int csock, bool skipauth)
Daniel P. Berrange13661082011-06-23 13:31:42 +01003830{
Gerd Hoffmann14f71432014-07-29 12:24:55 +02003831 VncDisplay *vs = vnc_display_find(id);
Daniel P. Berrange13661082011-06-23 13:31:42 +01003832
Gerd Hoffmannd616ccc2014-07-29 12:14:08 +02003833 if (!vs) {
3834 return;
3835 }
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003836 vnc_connect(vs, csock, skipauth, false);
Daniel P. Berrange13661082011-06-23 13:31:42 +01003837}
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003838
Gerd Hoffmann9634f4e2015-02-17 09:28:17 +01003839static void vnc_auto_assign_id(QemuOptsList *olist, QemuOpts *opts)
Gonglei27796722015-02-05 17:43:34 +08003840{
3841 int i = 2;
3842 char *id;
3843
3844 id = g_strdup("default");
3845 while (qemu_opts_find(olist, id)) {
3846 g_free(id);
3847 id = g_strdup_printf("vnc%d", i++);
3848 }
3849 qemu_opts_set_id(opts, id);
3850}
3851
Markus Armbruster70b94332015-02-13 12:50:26 +01003852QemuOpts *vnc_parse(const char *str, Error **errp)
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003853{
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003854 QemuOptsList *olist = qemu_find_opts("vnc");
Markus Armbruster70b94332015-02-13 12:50:26 +01003855 QemuOpts *opts = qemu_opts_parse(olist, str, true, errp);
Gonglei81607cb2015-03-12 15:33:45 +08003856 const char *id;
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003857
Gonglei81607cb2015-03-12 15:33:45 +08003858 if (!opts) {
3859 return NULL;
3860 }
3861
3862 id = qemu_opts_id(opts);
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003863 if (!id) {
3864 /* auto-assign id if not present */
Gonglei27796722015-02-05 17:43:34 +08003865 vnc_auto_assign_id(olist, opts);
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003866 }
Gerd Hoffmann9634f4e2015-02-17 09:28:17 +01003867 return opts;
3868}
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003869
Markus Armbruster28d0de72015-03-13 13:35:14 +01003870int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
Gerd Hoffmann9634f4e2015-02-17 09:28:17 +01003871{
3872 Error *local_err = NULL;
3873 char *id = (char *)qemu_opts_id(opts);
3874
3875 assert(id);
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003876 vnc_display_init(id);
3877 vnc_display_open(id, &local_err);
3878 if (local_err != NULL) {
Cole Robinsonbc119042015-05-05 11:07:18 -04003879 error_report("Failed to start VNC server: %s",
Gerd Hoffmann4db14622014-09-16 12:33:03 +02003880 error_get_pretty(local_err));
3881 error_free(local_err);
3882 exit(1);
3883 }
3884 return 0;
3885}
3886
3887static void vnc_register_config(void)
3888{
3889 qemu_add_opts(&qemu_vnc_opts);
3890}
3891machine_init(vnc_register_config);