blob: 06d6ca009ec82a3e1c5b28da5d52c47c1c28762c [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"
Paolo Bonzini9c17d612012-12-17 18:20:04 +010030#include "sysemu/sysemu.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010031#include "qemu/sockets.h"
32#include "qemu/timer.h"
33#include "qemu/acl.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010034#include "qapi/qmp/types.h"
Luiz Capitulino2b54aa82011-10-17 16:41:22 -020035#include "qmp-commands.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010036#include "qemu/osdep.h"
Gerd Hoffmann8d447d12013-12-02 14:27:18 +010037#include "ui/input.h"
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +020038#include "qapi-event.h"
bellard24236862006-04-30 21:28:36 +000039
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +010040#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
Stefano Stabellini2430ffe2009-08-03 10:56:01 +010041#define VNC_REFRESH_INTERVAL_INC 50
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +010042#define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE
Corentin Chary999342a2011-02-04 09:05:55 +010043static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
44static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
bellard24236862006-04-30 21:28:36 +000045
46#include "vnc_keysym.h"
ths70848512007-08-25 01:37:05 +000047#include "d3des.h"
48
aliguori753b4052009-02-16 14:59:30 +000049static VncDisplay *vnc_display; /* needed for info vnc */
bellarda9ce8592007-02-05 20:20:30 +000050
Gerd Hoffmannd467b672010-05-21 11:54:34 +020051static int vnc_cursor_define(VncState *vs);
Gerd Hoffmann7bc93182012-02-08 13:18:37 +010052static void vnc_release_modifiers(VncState *vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +020053
Gerd Hoffmann8cf36482011-11-24 18:10:49 +010054static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
55{
56#ifdef _VNC_DEBUG
57 static const char *mn[] = {
58 [0] = "undefined",
59 [VNC_SHARE_MODE_CONNECTING] = "connecting",
60 [VNC_SHARE_MODE_SHARED] = "shared",
61 [VNC_SHARE_MODE_EXCLUSIVE] = "exclusive",
62 [VNC_SHARE_MODE_DISCONNECTED] = "disconnected",
63 };
64 fprintf(stderr, "%s/%d: %s -> %s\n", __func__,
65 vs->csock, mn[vs->share_mode], mn[mode]);
66#endif
67
68 if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
69 vs->vd->num_exclusive--;
70 }
71 vs->share_mode = mode;
72 if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
73 vs->vd->num_exclusive++;
74 }
75}
76
aliguori1ff7df12009-03-06 20:27:05 +000077static char *addr_to_string(const char *format,
78 struct sockaddr_storage *sa,
79 socklen_t salen) {
80 char *addr;
81 char host[NI_MAXHOST];
82 char serv[NI_MAXSERV];
83 int err;
aliguori457772e2009-03-13 15:03:27 +000084 size_t addrlen;
aliguori1ff7df12009-03-06 20:27:05 +000085
86 if ((err = getnameinfo((struct sockaddr *)sa, salen,
87 host, sizeof(host),
88 serv, sizeof(serv),
89 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
90 VNC_DEBUG("Cannot resolve address %d: %s\n",
91 err, gai_strerror(err));
92 return NULL;
93 }
94
aliguori457772e2009-03-13 15:03:27 +000095 /* Enough for the existing format + the 2 vars we're
Stefan Weilf425c272009-06-06 17:00:31 +020096 * substituting in. */
aliguori457772e2009-03-13 15:03:27 +000097 addrlen = strlen(format) + strlen(host) + strlen(serv);
Anthony Liguori7267c092011-08-20 22:09:37 -050098 addr = g_malloc(addrlen + 1);
aliguori457772e2009-03-13 15:03:27 +000099 snprintf(addr, addrlen, format, host, serv);
100 addr[addrlen] = '\0';
aliguori1ff7df12009-03-06 20:27:05 +0000101
102 return addr;
103}
104
aliguori2f9606b2009-03-06 20:27:28 +0000105
106char *vnc_socket_local_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +0000107 struct sockaddr_storage sa;
108 socklen_t salen;
109
110 salen = sizeof(sa);
111 if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
112 return NULL;
113
114 return addr_to_string(format, &sa, salen);
115}
116
aliguori2f9606b2009-03-06 20:27:28 +0000117char *vnc_socket_remote_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +0000118 struct sockaddr_storage sa;
119 socklen_t salen;
120
121 salen = sizeof(sa);
122 if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
123 return NULL;
124
125 return addr_to_string(format, &sa, salen);
126}
127
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200128static VncBasicInfo *vnc_basic_info_get(struct sockaddr_storage *sa,
129 socklen_t salen)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200130{
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200131 VncBasicInfo *info;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200132 char host[NI_MAXHOST];
133 char serv[NI_MAXSERV];
134 int err;
135
136 if ((err = getnameinfo((struct sockaddr *)sa, salen,
137 host, sizeof(host),
138 serv, sizeof(serv),
139 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
140 VNC_DEBUG("Cannot resolve address %d: %s\n",
141 err, gai_strerror(err));
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200142 return NULL;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200143 }
144
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200145 info = g_malloc0(sizeof(VncBasicInfo));
146 info->host = g_strdup(host);
147 info->service = g_strdup(serv);
148 info->family = inet_netfamily(sa->ss_family);
149 return info;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200150}
151
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200152static VncBasicInfo *vnc_basic_info_get_from_server_addr(int fd)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200153{
154 struct sockaddr_storage sa;
155 socklen_t salen;
156
157 salen = sizeof(sa);
158 if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200159 return NULL;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200160 }
161
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200162 return vnc_basic_info_get(&sa, salen);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200163}
164
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200165static VncBasicInfo *vnc_basic_info_get_from_remote_addr(int fd)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200166{
167 struct sockaddr_storage sa;
168 socklen_t salen;
169
170 salen = sizeof(sa);
171 if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200172 return NULL;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200173 }
174
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200175 return vnc_basic_info_get(&sa, salen);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200176}
177
aliguori1ff7df12009-03-06 20:27:05 +0000178static const char *vnc_auth_name(VncDisplay *vd) {
179 switch (vd->auth) {
180 case VNC_AUTH_INVALID:
181 return "invalid";
182 case VNC_AUTH_NONE:
183 return "none";
184 case VNC_AUTH_VNC:
185 return "vnc";
186 case VNC_AUTH_RA2:
187 return "ra2";
188 case VNC_AUTH_RA2NE:
189 return "ra2ne";
190 case VNC_AUTH_TIGHT:
191 return "tight";
192 case VNC_AUTH_ULTRA:
193 return "ultra";
194 case VNC_AUTH_TLS:
195 return "tls";
196 case VNC_AUTH_VENCRYPT:
197#ifdef CONFIG_VNC_TLS
198 switch (vd->subauth) {
199 case VNC_AUTH_VENCRYPT_PLAIN:
200 return "vencrypt+plain";
201 case VNC_AUTH_VENCRYPT_TLSNONE:
202 return "vencrypt+tls+none";
203 case VNC_AUTH_VENCRYPT_TLSVNC:
204 return "vencrypt+tls+vnc";
205 case VNC_AUTH_VENCRYPT_TLSPLAIN:
206 return "vencrypt+tls+plain";
207 case VNC_AUTH_VENCRYPT_X509NONE:
208 return "vencrypt+x509+none";
209 case VNC_AUTH_VENCRYPT_X509VNC:
210 return "vencrypt+x509+vnc";
211 case VNC_AUTH_VENCRYPT_X509PLAIN:
212 return "vencrypt+x509+plain";
aliguori28a76be2009-03-06 20:27:40 +0000213 case VNC_AUTH_VENCRYPT_TLSSASL:
214 return "vencrypt+tls+sasl";
215 case VNC_AUTH_VENCRYPT_X509SASL:
216 return "vencrypt+x509+sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000217 default:
218 return "vencrypt";
219 }
220#else
221 return "vencrypt";
222#endif
aliguori2f9606b2009-03-06 20:27:28 +0000223 case VNC_AUTH_SASL:
aliguori28a76be2009-03-06 20:27:40 +0000224 return "sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000225 }
226 return "unknown";
227}
228
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200229static VncServerInfo *vnc_server_info_get(void)
Luiz Capitulinoa7789382010-01-14 14:50:53 -0200230{
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200231 VncServerInfo *info;
232 VncBasicInfo *bi = vnc_basic_info_get_from_server_addr(vnc_display->lsock);
233 if (!bi) {
234 return NULL;
Luiz Capitulinoa7789382010-01-14 14:50:53 -0200235 }
236
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200237 info = g_malloc(sizeof(*info));
238 info->base = bi;
239 info->has_auth = true;
240 info->auth = g_strdup(vnc_auth_name(vnc_display));
241 return info;
Luiz Capitulinoa7789382010-01-14 14:50:53 -0200242}
243
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200244static void vnc_client_cache_auth(VncState *client)
aliguori1ff7df12009-03-06 20:27:05 +0000245{
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200246 if (!client->info) {
247 return;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200248 }
aliguori1263b7d2009-03-06 20:27:32 +0000249
250#ifdef CONFIG_VNC_TLS
251 if (client->tls.session &&
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200252 client->tls.dname) {
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200253 client->info->has_x509_dname = true;
254 client->info->x509_dname = g_strdup(client->tls.dname);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200255 }
aliguori1263b7d2009-03-06 20:27:32 +0000256#endif
257#ifdef CONFIG_VNC_SASL
258 if (client->sasl.conn &&
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200259 client->sasl.username) {
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200260 client->info->has_sasl_username = true;
261 client->info->sasl_username = g_strdup(client->sasl.username);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200262 }
263#endif
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200264}
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200265
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200266static void vnc_client_cache_addr(VncState *client)
267{
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200268 VncBasicInfo *bi = vnc_basic_info_get_from_remote_addr(client->csock);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200269
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200270 if (bi) {
271 client->info = g_malloc0(sizeof(*client->info));
272 client->info->base = bi;
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200273 }
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200274}
275
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200276static void vnc_qmp_event(VncState *vs, QAPIEvent event)
Luiz Capitulino586153d2010-01-14 14:50:57 -0200277{
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200278 VncServerInfo *si;
Luiz Capitulino586153d2010-01-14 14:50:57 -0200279
280 if (!vs->info) {
281 return;
282 }
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200283 g_assert(vs->info->base);
Luiz Capitulino586153d2010-01-14 14:50:57 -0200284
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200285 si = vnc_server_info_get();
286 if (!si) {
Luiz Capitulino586153d2010-01-14 14:50:57 -0200287 return;
288 }
289
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200290 switch (event) {
291 case QAPI_EVENT_VNC_CONNECTED:
292 qapi_event_send_vnc_connected(si, vs->info->base, &error_abort);
293 break;
294 case QAPI_EVENT_VNC_INITIALIZED:
295 qapi_event_send_vnc_initialized(si, vs->info, &error_abort);
296 break;
297 case QAPI_EVENT_VNC_DISCONNECTED:
298 qapi_event_send_vnc_disconnected(si, vs->info, &error_abort);
299 break;
300 default:
301 break;
302 }
Luiz Capitulino586153d2010-01-14 14:50:57 -0200303
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +0200304 qapi_free_VncServerInfo(si);
Luiz Capitulino586153d2010-01-14 14:50:57 -0200305}
306
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200307static VncClientInfo *qmp_query_vnc_client(const VncState *client)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200308{
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200309 struct sockaddr_storage sa;
310 socklen_t salen = sizeof(sa);
311 char host[NI_MAXHOST];
312 char serv[NI_MAXSERV];
313 VncClientInfo *info;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200314
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200315 if (getpeername(client->csock, (struct sockaddr *)&sa, &salen) < 0) {
316 return NULL;
317 }
318
319 if (getnameinfo((struct sockaddr *)&sa, salen,
320 host, sizeof(host),
321 serv, sizeof(serv),
322 NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
323 return NULL;
324 }
325
326 info = g_malloc0(sizeof(*info));
Wenchao Xiaa5895692014-06-18 08:43:30 +0200327 info->base = g_malloc0(sizeof(*info->base));
328 info->base->host = g_strdup(host);
329 info->base->service = g_strdup(serv);
330 info->base->family = inet_netfamily(sa.ss_family);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200331
332#ifdef CONFIG_VNC_TLS
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200333 if (client->tls.session && client->tls.dname) {
334 info->has_x509_dname = true;
335 info->x509_dname = g_strdup(client->tls.dname);
336 }
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200337#endif
338#ifdef CONFIG_VNC_SASL
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200339 if (client->sasl.conn && client->sasl.username) {
340 info->has_sasl_username = true;
341 info->sasl_username = g_strdup(client->sasl.username);
342 }
aliguori1263b7d2009-03-06 20:27:32 +0000343#endif
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200344
345 return info;
aliguori1ff7df12009-03-06 20:27:05 +0000346}
347
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200348VncInfo *qmp_query_vnc(Error **errp)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200349{
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200350 VncInfo *info = g_malloc0(sizeof(*info));
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200351
aliguori1ff7df12009-03-06 20:27:05 +0000352 if (vnc_display == NULL || vnc_display->display == NULL) {
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200353 info->enabled = false;
aliguori1ff7df12009-03-06 20:27:05 +0000354 } else {
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200355 VncClientInfoList *cur_item = NULL;
356 struct sockaddr_storage sa;
357 socklen_t salen = sizeof(sa);
358 char host[NI_MAXHOST];
359 char serv[NI_MAXSERV];
Amit Shah41b4bef2010-02-05 16:34:05 +0530360 VncState *client;
bellarda9ce8592007-02-05 20:20:30 +0000361
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200362 info->enabled = true;
363
364 /* for compatibility with the original command */
365 info->has_clients = true;
366
Amit Shah41b4bef2010-02-05 16:34:05 +0530367 QTAILQ_FOREACH(client, &vnc_display->clients, next) {
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200368 VncClientInfoList *cinfo = g_malloc0(sizeof(*info));
369 cinfo->value = qmp_query_vnc_client(client);
370
371 /* XXX: waiting for the qapi to support GSList */
372 if (!cur_item) {
373 info->clients = cur_item = cinfo;
374 } else {
375 cur_item->next = cinfo;
376 cur_item = cinfo;
aliguori1ff7df12009-03-06 20:27:05 +0000377 }
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200378 }
379
Paolo Bonzini417b0b82012-10-10 14:30:58 +0200380 if (vnc_display->lsock == -1) {
381 return info;
382 }
383
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200384 if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa,
385 &salen) == -1) {
386 error_set(errp, QERR_UNDEFINED_ERROR);
387 goto out_error;
aliguori1ff7df12009-03-06 20:27:05 +0000388 }
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200389
390 if (getnameinfo((struct sockaddr *)&sa, salen,
391 host, sizeof(host),
392 serv, sizeof(serv),
393 NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
394 error_set(errp, QERR_UNDEFINED_ERROR);
395 goto out_error;
396 }
397
398 info->has_host = true;
399 info->host = g_strdup(host);
400
401 info->has_service = true;
402 info->service = g_strdup(serv);
403
404 info->has_family = true;
Wenchao Xiaa5895692014-06-18 08:43:30 +0200405 info->family = inet_netfamily(sa.ss_family);
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200406
407 info->has_auth = true;
408 info->auth = g_strdup(vnc_auth_name(vnc_display));
bellarda9ce8592007-02-05 20:20:30 +0000409 }
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200410
411 return info;
412
413out_error:
414 qapi_free_VncInfo(info);
415 return NULL;
bellarda9ce8592007-02-05 20:20:30 +0000416}
417
bellard24236862006-04-30 21:28:36 +0000418/* TODO
419 1) Get the queue working for IO.
420 2) there is some weirdness when using the -S option (the screen is grey
421 and not totally invalidated
422 3) resolutions > 1024
423*/
424
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100425static int vnc_update_client(VncState *vs, int has_dirty, bool sync);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200426static void vnc_disconnect_start(VncState *vs);
bellard24236862006-04-30 21:28:36 +0000427
aliguori753b4052009-02-16 14:59:30 +0000428static void vnc_colordepth(VncState *vs);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100429static void framebuffer_update_request(VncState *vs, int incremental,
430 int x_position, int y_position,
431 int w, int h);
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +0100432static void vnc_refresh(DisplayChangeListener *dcl);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100433static int vnc_refresh_server_surface(VncDisplay *vd);
aliguori7eac3a82008-09-15 16:03:41 +0000434
Peter Lievenbea60dd2014-06-30 10:57:51 +0200435static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
436 VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT),
437 int width, int height,
438 int x, int y, int w, int h) {
Peter Lieven91937222014-01-08 10:08:37 +0100439 /* this is needed this to ensure we updated all affected
440 * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100441 w += (x % VNC_DIRTY_PIXELS_PER_BIT);
442 x -= (x % VNC_DIRTY_PIXELS_PER_BIT);
balrog0486e8a2007-12-11 22:31:32 +0000443
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200444 x = MIN(x, width);
445 y = MIN(y, height);
446 w = MIN(x + w, width) - x;
Peter Lieven91937222014-01-08 10:08:37 +0100447 h = MIN(y + h, height);
balrog788abf82008-05-20 00:07:58 +0000448
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100449 for (; y < h; y++) {
Peter Lievenbea60dd2014-06-30 10:57:51 +0200450 bitmap_set(dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
Peter Lieven91937222014-01-08 10:08:37 +0100451 DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100452 }
bellard24236862006-04-30 21:28:36 +0000453}
454
Peter Lievenbea60dd2014-06-30 10:57:51 +0200455static void vnc_dpy_update(DisplayChangeListener *dcl,
456 int x, int y, int w, int h)
457{
458 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
459 struct VncSurface *s = &vd->guest;
460 int width = pixman_image_get_width(vd->server);
461 int height = pixman_image_get_height(vd->server);
462
463 vnc_set_area_dirty(s->dirty, width, height, x, y, w, h);
464}
465
Corentin Chary70a45682010-05-03 14:31:34 +0200466void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
467 int32_t encoding)
bellard24236862006-04-30 21:28:36 +0000468{
469 vnc_write_u16(vs, x);
470 vnc_write_u16(vs, y);
471 vnc_write_u16(vs, w);
472 vnc_write_u16(vs, h);
473
474 vnc_write_s32(vs, encoding);
475}
476
aliguori2f9606b2009-03-06 20:27:28 +0000477void buffer_reserve(Buffer *buffer, size_t len)
aliguori89064282009-02-02 15:58:47 +0000478{
479 if ((buffer->capacity - buffer->offset) < len) {
aliguori28a76be2009-03-06 20:27:40 +0000480 buffer->capacity += (len + 1024);
Anthony Liguori7267c092011-08-20 22:09:37 -0500481 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
aliguori28a76be2009-03-06 20:27:40 +0000482 if (buffer->buffer == NULL) {
483 fprintf(stderr, "vnc: out of memory\n");
484 exit(1);
485 }
aliguori89064282009-02-02 15:58:47 +0000486 }
487}
488
Blue Swirl71a8cde2012-10-28 11:04:48 +0000489static int buffer_empty(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000490{
491 return buffer->offset == 0;
492}
493
Tim Hardeck7536ee42013-01-21 11:04:44 +0100494uint8_t *buffer_end(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000495{
496 return buffer->buffer + buffer->offset;
497}
498
aliguori2f9606b2009-03-06 20:27:28 +0000499void buffer_reset(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000500{
aliguori28a76be2009-03-06 20:27:40 +0000501 buffer->offset = 0;
aliguori89064282009-02-02 15:58:47 +0000502}
503
Corentin Chary5d418e32010-05-19 09:24:07 +0200504void buffer_free(Buffer *buffer)
505{
Anthony Liguori7267c092011-08-20 22:09:37 -0500506 g_free(buffer->buffer);
Corentin Chary5d418e32010-05-19 09:24:07 +0200507 buffer->offset = 0;
508 buffer->capacity = 0;
509 buffer->buffer = NULL;
510}
511
aliguori2f9606b2009-03-06 20:27:28 +0000512void buffer_append(Buffer *buffer, const void *data, size_t len)
aliguori89064282009-02-02 15:58:47 +0000513{
514 memcpy(buffer->buffer + buffer->offset, data, len);
515 buffer->offset += len;
516}
517
Tim Hardeck32ed2682013-01-21 11:04:43 +0100518void buffer_advance(Buffer *buf, size_t len)
519{
520 memmove(buf->buffer, buf->buffer + len,
521 (buf->offset - len));
522 buf->offset -= len;
523}
524
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200525static void vnc_desktop_resize(VncState *vs)
526{
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200527 if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
528 return;
529 }
Peter Lievenbea60dd2014-06-30 10:57:51 +0200530 if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
531 vs->client_height == pixman_image_get_height(vs->vd->server)) {
Gerd Hoffmann1d4b6382010-05-25 18:25:20 +0200532 return;
533 }
Peter Lievenbea60dd2014-06-30 10:57:51 +0200534 vs->client_width = pixman_image_get_width(vs->vd->server);
535 vs->client_height = pixman_image_get_height(vs->vd->server);
Corentin Charybd023f92010-07-07 20:58:02 +0200536 vnc_lock_output(vs);
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200537 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
538 vnc_write_u8(vs, 0);
539 vnc_write_u16(vs, 1); /* number of rects */
Gerd Hoffmann5862d192010-05-25 18:25:18 +0200540 vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200541 VNC_ENCODING_DESKTOPRESIZE);
Corentin Charybd023f92010-07-07 20:58:02 +0200542 vnc_unlock_output(vs);
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200543 vnc_flush(vs);
544}
545
Corentin Charybd023f92010-07-07 20:58:02 +0200546static void vnc_abort_display_jobs(VncDisplay *vd)
547{
548 VncState *vs;
549
550 QTAILQ_FOREACH(vs, &vd->clients, next) {
551 vnc_lock_output(vs);
552 vs->abort = true;
553 vnc_unlock_output(vs);
554 }
555 QTAILQ_FOREACH(vs, &vd->clients, next) {
556 vnc_jobs_join(vs);
557 }
558 QTAILQ_FOREACH(vs, &vd->clients, next) {
559 vnc_lock_output(vs);
560 vs->abort = false;
561 vnc_unlock_output(vs);
562 }
563}
Corentin Charybd023f92010-07-07 20:58:02 +0200564
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200565int vnc_server_fb_stride(VncDisplay *vd)
566{
567 return pixman_image_get_stride(vd->server);
568}
569
570void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
571{
572 uint8_t *ptr;
573
574 ptr = (uint8_t *)pixman_image_get_data(vd->server);
575 ptr += y * vnc_server_fb_stride(vd);
576 ptr += x * VNC_SERVER_FB_BYTES;
577 return ptr;
578}
579
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +0100580static void vnc_dpy_switch(DisplayChangeListener *dcl,
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +0100581 DisplaySurface *surface)
aliguori753b4052009-02-16 14:59:30 +0000582{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +0100583 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Amit Shah41b4bef2010-02-05 16:34:05 +0530584 VncState *vs;
Peter Lievenbea60dd2014-06-30 10:57:51 +0200585 int width, height;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100586
Corentin Charybd023f92010-07-07 20:58:02 +0200587 vnc_abort_display_jobs(vd);
588
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100589 /* server surface */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200590 qemu_pixman_image_unref(vd->server);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100591 vd->ds = surface;
Peter Lievenbea60dd2014-06-30 10:57:51 +0200592 width = MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
593 VNC_DIRTY_PIXELS_PER_BIT));
594 height = MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200595 vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
Peter Lievenbea60dd2014-06-30 10:57:51 +0200596 width, height, NULL, 0);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100597
598 /* guest surface */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200599#if 0 /* FIXME */
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100600 if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
601 console_color_init(ds);
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200602#endif
603 qemu_pixman_image_unref(vd->guest.fb);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100604 vd->guest.fb = pixman_image_ref(surface->image);
605 vd->guest.format = surface->format;
Peter Lievenbea60dd2014-06-30 10:57:51 +0200606 memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty));
607 vnc_set_area_dirty(vd->guest.dirty, width, height, 0, 0,
608 width, height);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100609
Amit Shah41b4bef2010-02-05 16:34:05 +0530610 QTAILQ_FOREACH(vs, &vd->clients, next) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100611 vnc_colordepth(vs);
Gerd Hoffmann1d4b6382010-05-25 18:25:20 +0200612 vnc_desktop_resize(vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200613 if (vs->vd->cursor) {
614 vnc_cursor_define(vs);
615 }
Peter Lievenbea60dd2014-06-30 10:57:51 +0200616 memset(vs->dirty, 0x00, sizeof(vs->dirty));
617 vnc_set_area_dirty(vs->dirty, width, height, 0, 0,
618 width, height);
aliguori753b4052009-02-16 14:59:30 +0000619 }
620}
621
bellard35127792006-05-14 18:11:49 +0000622/* fastest code */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200623static void vnc_write_pixels_copy(VncState *vs,
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200624 void *pixels, int size)
bellard35127792006-05-14 18:11:49 +0000625{
626 vnc_write(vs, pixels, size);
627}
628
629/* slowest but generic code. */
Corentin Chary70a45682010-05-03 14:31:34 +0200630void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
bellard35127792006-05-14 18:11:49 +0000631{
aliguori7eac3a82008-09-15 16:03:41 +0000632 uint8_t r, g, b;
bellard35127792006-05-14 18:11:49 +0000633
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200634#if VNC_SERVER_FB_FORMAT == PIXMAN_FORMAT(32, PIXMAN_TYPE_ARGB, 0, 8, 8, 8)
635 r = (((v & 0x00ff0000) >> 16) << vs->client_pf.rbits) >> 8;
636 g = (((v & 0x0000ff00) >> 8) << vs->client_pf.gbits) >> 8;
637 b = (((v & 0x000000ff) >> 0) << vs->client_pf.bbits) >> 8;
638#else
639# error need some bits here if you change VNC_SERVER_FB_FORMAT
640#endif
641 v = (r << vs->client_pf.rshift) |
642 (g << vs->client_pf.gshift) |
643 (b << vs->client_pf.bshift);
644 switch (vs->client_pf.bytes_per_pixel) {
bellard35127792006-05-14 18:11:49 +0000645 case 1:
646 buf[0] = v;
647 break;
648 case 2:
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200649 if (vs->client_be) {
bellard35127792006-05-14 18:11:49 +0000650 buf[0] = v >> 8;
651 buf[1] = v;
652 } else {
653 buf[1] = v >> 8;
654 buf[0] = v;
655 }
656 break;
657 default:
658 case 4:
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200659 if (vs->client_be) {
bellard35127792006-05-14 18:11:49 +0000660 buf[0] = v >> 24;
661 buf[1] = v >> 16;
662 buf[2] = v >> 8;
663 buf[3] = v;
664 } else {
665 buf[3] = v >> 24;
666 buf[2] = v >> 16;
667 buf[1] = v >> 8;
668 buf[0] = v;
669 }
670 break;
671 }
672}
673
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200674static void vnc_write_pixels_generic(VncState *vs,
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200675 void *pixels1, int size)
bellard35127792006-05-14 18:11:49 +0000676{
bellard35127792006-05-14 18:11:49 +0000677 uint8_t buf[4];
bellard35127792006-05-14 18:11:49 +0000678
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200679 if (VNC_SERVER_FB_BYTES == 4) {
aliguori7eac3a82008-09-15 16:03:41 +0000680 uint32_t *pixels = pixels1;
681 int n, i;
682 n = size >> 2;
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200683 for (i = 0; i < n; i++) {
aliguori7eac3a82008-09-15 16:03:41 +0000684 vnc_convert_pixel(vs, buf, pixels[i]);
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200685 vnc_write(vs, buf, vs->client_pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000686 }
bellard35127792006-05-14 18:11:49 +0000687 }
688}
689
Corentin Charya8852112010-05-19 09:24:09 +0200690int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000691{
692 int i;
ths60fe76f2007-12-16 03:02:09 +0000693 uint8_t *row;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100694 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000695
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200696 row = vnc_server_fb_ptr(vd, x, y);
bellard24236862006-04-30 21:28:36 +0000697 for (i = 0; i < h; i++) {
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200698 vs->write_pixels(vs, row, w * VNC_SERVER_FB_BYTES);
699 row += vnc_server_fb_stride(vd);
bellard24236862006-04-30 21:28:36 +0000700 }
Corentin Charya8852112010-05-19 09:24:09 +0200701 return 1;
bellard24236862006-04-30 21:28:36 +0000702}
703
Corentin Charybd023f92010-07-07 20:58:02 +0200704int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000705{
Corentin Charya8852112010-05-19 09:24:09 +0200706 int n = 0;
707
aliguorifb437312009-02-02 15:58:43 +0000708 switch(vs->vnc_encoding) {
aliguori28a76be2009-03-06 20:27:40 +0000709 case VNC_ENCODING_ZLIB:
Corentin Charya8852112010-05-19 09:24:09 +0200710 n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
aliguori28a76be2009-03-06 20:27:40 +0000711 break;
712 case VNC_ENCODING_HEXTILE:
713 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
Corentin Charya8852112010-05-19 09:24:09 +0200714 n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
aliguori28a76be2009-03-06 20:27:40 +0000715 break;
Corentin Chary380282b2010-05-19 09:24:10 +0200716 case VNC_ENCODING_TIGHT:
717 n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
718 break;
Corentin Charyefe556a2010-07-07 20:57:56 +0200719 case VNC_ENCODING_TIGHT_PNG:
720 n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
721 break;
Corentin Chary148954f2011-02-04 09:06:01 +0100722 case VNC_ENCODING_ZRLE:
723 n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
724 break;
725 case VNC_ENCODING_ZYWRLE:
726 n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
727 break;
aliguori28a76be2009-03-06 20:27:40 +0000728 default:
729 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
Corentin Charya8852112010-05-19 09:24:09 +0200730 n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
aliguori28a76be2009-03-06 20:27:40 +0000731 break;
aliguorifb437312009-02-02 15:58:43 +0000732 }
Corentin Charya8852112010-05-19 09:24:09 +0200733 return n;
bellard24236862006-04-30 21:28:36 +0000734}
735
aliguori753b4052009-02-16 14:59:30 +0000736static 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 +0000737{
Gerd Hoffmann3e28c9a2009-07-27 17:10:48 +0200738 /* send bitblit op to the vnc client */
Corentin Charybd023f92010-07-07 20:58:02 +0200739 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +0100740 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
bellard24236862006-04-30 21:28:36 +0000741 vnc_write_u8(vs, 0);
742 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000743 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
bellard24236862006-04-30 21:28:36 +0000744 vnc_write_u16(vs, src_x);
745 vnc_write_u16(vs, src_y);
Corentin Charybd023f92010-07-07 20:58:02 +0200746 vnc_unlock_output(vs);
bellard24236862006-04-30 21:28:36 +0000747 vnc_flush(vs);
748}
749
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100750static void vnc_dpy_copy(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100751 int src_x, int src_y,
752 int dst_x, int dst_y, int w, int h)
aliguori753b4052009-02-16 14:59:30 +0000753{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +0100754 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200755 VncState *vs, *vn;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100756 uint8_t *src_row;
757 uint8_t *dst_row;
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200758 int i, x, y, pitch, inc, w_lim, s;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100759 int cmp_bytes;
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200760
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100761 vnc_refresh_server_surface(vd);
Amit Shah41b4bef2010-02-05 16:34:05 +0530762 QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200763 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
764 vs->force_update = 1;
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100765 vnc_update_client(vs, 1, true);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200766 /* vs might be free()ed here */
767 }
768 }
769
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100770 /* do bitblit op on the local surface too */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200771 pitch = vnc_server_fb_stride(vd);
772 src_row = vnc_server_fb_ptr(vd, src_x, src_y);
773 dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100774 y = dst_y;
775 inc = 1;
776 if (dst_y > src_y) {
777 /* copy backwards */
778 src_row += pitch * (h-1);
779 dst_row += pitch * (h-1);
780 pitch = -pitch;
781 y = dst_y + h - 1;
782 inc = -1;
783 }
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100784 w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
785 if (w_lim < 0) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100786 w_lim = w;
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100787 } else {
788 w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT);
789 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100790 for (i = 0; i < h; i++) {
791 for (x = 0; x <= w_lim;
792 x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
793 if (x == w_lim) {
794 if ((s = w - w_lim) == 0)
795 break;
796 } else if (!x) {
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100797 s = (VNC_DIRTY_PIXELS_PER_BIT -
798 (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100799 s = MIN(s, w_lim);
800 } else {
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100801 s = VNC_DIRTY_PIXELS_PER_BIT;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100802 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200803 cmp_bytes = s * VNC_SERVER_FB_BYTES;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100804 if (memcmp(src_row, dst_row, cmp_bytes) == 0)
805 continue;
806 memmove(dst_row, src_row, cmp_bytes);
Amit Shah41b4bef2010-02-05 16:34:05 +0530807 QTAILQ_FOREACH(vs, &vd->clients, next) {
808 if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100809 set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT),
810 vs->dirty[y]);
Amit Shah41b4bef2010-02-05 16:34:05 +0530811 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100812 }
813 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200814 src_row += pitch - w * VNC_SERVER_FB_BYTES;
815 dst_row += pitch - w * VNC_SERVER_FB_BYTES;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100816 y += inc;
817 }
818
Amit Shah41b4bef2010-02-05 16:34:05 +0530819 QTAILQ_FOREACH(vs, &vd->clients, next) {
820 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
aliguori753b4052009-02-16 14:59:30 +0000821 vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
Amit Shah41b4bef2010-02-05 16:34:05 +0530822 }
aliguori753b4052009-02-16 14:59:30 +0000823 }
824}
825
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100826static void vnc_mouse_set(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100827 int x, int y, int visible)
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200828{
829 /* can we ask the client(s) to move the pointer ??? */
830}
831
832static int vnc_cursor_define(VncState *vs)
833{
834 QEMUCursor *c = vs->vd->cursor;
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200835 int isize;
836
837 if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
Corentin Charyd01f9592010-07-07 20:58:03 +0200838 vnc_lock_output(vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200839 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
840 vnc_write_u8(vs, 0); /* padding */
841 vnc_write_u16(vs, 1); /* # of rects */
842 vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
843 VNC_ENCODING_RICH_CURSOR);
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200844 isize = c->width * c->height * vs->client_pf.bytes_per_pixel;
845 vnc_write_pixels_generic(vs, c->data, isize);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200846 vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
Corentin Charyd01f9592010-07-07 20:58:03 +0200847 vnc_unlock_output(vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200848 return 0;
849 }
850 return -1;
851}
852
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100853static void vnc_dpy_cursor_define(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100854 QEMUCursor *c)
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200855{
856 VncDisplay *vd = vnc_display;
857 VncState *vs;
858
859 cursor_put(vd->cursor);
Anthony Liguori7267c092011-08-20 22:09:37 -0500860 g_free(vd->cursor_mask);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200861
862 vd->cursor = c;
863 cursor_get(vd->cursor);
864 vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
Anthony Liguori7267c092011-08-20 22:09:37 -0500865 vd->cursor_mask = g_malloc0(vd->cursor_msize);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200866 cursor_get_mono_mask(c, 0, vd->cursor_mask);
867
868 QTAILQ_FOREACH(vs, &vd->clients, next) {
869 vnc_cursor_define(vs);
870 }
871}
872
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100873static int find_and_clear_dirty_height(struct VncState *vs,
Corentin Chary6c71a532011-02-04 09:06:06 +0100874 int y, int last_x, int x, int height)
bellard24236862006-04-30 21:28:36 +0000875{
876 int h;
877
Corentin Chary6c71a532011-02-04 09:06:06 +0100878 for (h = 1; h < (height - y); h++) {
Corentin Charybc2429b2011-02-04 09:06:05 +0100879 if (!test_bit(last_x, vs->dirty[y + h])) {
aliguori28a76be2009-03-06 20:27:40 +0000880 break;
Corentin Charybc2429b2011-02-04 09:06:05 +0100881 }
Peter Lieven863d7c92014-01-08 10:08:36 +0100882 bitmap_clear(vs->dirty[y + h], last_x, x - last_x);
bellard24236862006-04-30 21:28:36 +0000883 }
884
885 return h;
886}
887
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100888static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
bellard24236862006-04-30 21:28:36 +0000889{
bellard24236862006-04-30 21:28:36 +0000890 if (vs->need_update && vs->csock != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100891 VncDisplay *vd = vs->vd;
Corentin Charybd023f92010-07-07 20:58:02 +0200892 VncJob *job;
aliguori28a76be2009-03-06 20:27:40 +0000893 int y;
Peter Lieven2f487a3d2014-03-17 18:38:58 +0100894 int height, width;
Corentin Charybd023f92010-07-07 20:58:02 +0200895 int n = 0;
896
Stefano Stabellini703bc682009-08-03 10:54:05 +0100897 if (vs->output.offset && !vs->audio_cap && !vs->force_update)
aliguoric522d0e2009-03-20 15:59:24 +0000898 /* kernel send buffers are full -> drop frames to throttle */
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100899 return 0;
balroga0ecfb72008-01-13 23:51:53 +0000900
Stefano Stabellini703bc682009-08-03 10:54:05 +0100901 if (!has_dirty && !vs->audio_cap && !vs->force_update)
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100902 return 0;
bellard24236862006-04-30 21:28:36 +0000903
aliguori6baebed2009-03-20 15:59:14 +0000904 /*
905 * Send screen updates to the vnc client using the server
906 * surface and server dirty map. guest surface updates
907 * happening in parallel don't disturb us, the next pass will
908 * send them to the client.
909 */
Corentin Charybd023f92010-07-07 20:58:02 +0200910 job = vnc_job_new(vs);
bellard24236862006-04-30 21:28:36 +0000911
Peter Lievenbea60dd2014-06-30 10:57:51 +0200912 height = pixman_image_get_height(vd->server);
913 width = pixman_image_get_width(vd->server);
Gerd Hoffmann847ce6a2010-05-25 18:25:19 +0200914
Peter Lieven12b316d2014-01-08 10:08:35 +0100915 y = 0;
916 for (;;) {
917 int x, h;
918 unsigned long x2;
919 unsigned long offset = find_next_bit((unsigned long *) &vs->dirty,
920 height * VNC_DIRTY_BPL(vs),
921 y * VNC_DIRTY_BPL(vs));
922 if (offset == height * VNC_DIRTY_BPL(vs)) {
923 /* no more dirty bits */
924 break;
aliguori28a76be2009-03-06 20:27:40 +0000925 }
Peter Lieven12b316d2014-01-08 10:08:35 +0100926 y = offset / VNC_DIRTY_BPL(vs);
927 x = offset % VNC_DIRTY_BPL(vs);
928 x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y],
929 VNC_DIRTY_BPL(vs), x);
930 bitmap_clear(vs->dirty[y], x, x2 - x);
931 h = find_and_clear_dirty_height(vs, y, x, x2, height);
Peter Lieven2f487a3d2014-03-17 18:38:58 +0100932 x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT);
933 if (x2 > x) {
934 n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y,
935 (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h);
936 }
aliguori28a76be2009-03-06 20:27:40 +0000937 }
Corentin Charybd023f92010-07-07 20:58:02 +0200938
939 vnc_job_push(job);
Gerd Hoffmanneb214ff2014-06-13 10:23:10 +0200940 if (sync) {
941 vnc_jobs_join(vs);
942 }
aliguoric522d0e2009-03-20 15:59:24 +0000943 vs->force_update = 0;
Corentin Charybd023f92010-07-07 20:58:02 +0200944 return n;
bellard24236862006-04-30 21:28:36 +0000945 }
bellard24236862006-04-30 21:28:36 +0000946
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100947 if (vs->csock == -1) {
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200948 vnc_disconnect_finish(vs);
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100949 } else if (sync) {
950 vnc_jobs_join(vs);
951 }
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100952
953 return 0;
bellard24236862006-04-30 21:28:36 +0000954}
955
malc429a8ed2008-12-01 20:57:48 +0000956/* audio */
957static void audio_capture_notify(void *opaque, audcnotification_e cmd)
958{
959 VncState *vs = opaque;
960
961 switch (cmd) {
962 case AUD_CNOTIFY_DISABLE:
Corentin Charybd023f92010-07-07 20:58:02 +0200963 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +0100964 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
965 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
966 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
Corentin Charybd023f92010-07-07 20:58:02 +0200967 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +0000968 vnc_flush(vs);
969 break;
970
971 case AUD_CNOTIFY_ENABLE:
Corentin Charybd023f92010-07-07 20:58:02 +0200972 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +0100973 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
974 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
975 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
Corentin Charybd023f92010-07-07 20:58:02 +0200976 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +0000977 vnc_flush(vs);
978 break;
979 }
980}
981
982static void audio_capture_destroy(void *opaque)
983{
984}
985
986static void audio_capture(void *opaque, void *buf, int size)
987{
988 VncState *vs = opaque;
989
Corentin Charybd023f92010-07-07 20:58:02 +0200990 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +0100991 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
992 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
993 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
malc429a8ed2008-12-01 20:57:48 +0000994 vnc_write_u32(vs, size);
995 vnc_write(vs, buf, size);
Corentin Charybd023f92010-07-07 20:58:02 +0200996 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +0000997 vnc_flush(vs);
998}
999
1000static void audio_add(VncState *vs)
1001{
1002 struct audio_capture_ops ops;
1003
1004 if (vs->audio_cap) {
Cole Robinson027a79c2014-03-21 19:42:21 -04001005 error_report("audio already running");
malc429a8ed2008-12-01 20:57:48 +00001006 return;
1007 }
1008
1009 ops.notify = audio_capture_notify;
1010 ops.destroy = audio_capture_destroy;
1011 ops.capture = audio_capture;
1012
malc1a7dafc2009-05-14 03:11:35 +04001013 vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
malc429a8ed2008-12-01 20:57:48 +00001014 if (!vs->audio_cap) {
Cole Robinson027a79c2014-03-21 19:42:21 -04001015 error_report("Failed to add audio capture");
malc429a8ed2008-12-01 20:57:48 +00001016 }
1017}
1018
1019static void audio_del(VncState *vs)
1020{
1021 if (vs->audio_cap) {
1022 AUD_del_capture(vs->audio_cap, vs);
1023 vs->audio_cap = NULL;
1024 }
1025}
1026
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001027static void vnc_disconnect_start(VncState *vs)
1028{
1029 if (vs->csock == -1)
1030 return;
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01001031 vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001032 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
1033 closesocket(vs->csock);
1034 vs->csock = -1;
1035}
1036
Tim Hardeck7536ee42013-01-21 11:04:44 +01001037void vnc_disconnect_finish(VncState *vs)
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001038{
Corentin Chary7d964c92011-02-04 09:05:56 +01001039 int i;
1040
Corentin Charybd023f92010-07-07 20:58:02 +02001041 vnc_jobs_join(vs); /* Wait encoding jobs */
1042
1043 vnc_lock_output(vs);
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +02001044 vnc_qmp_event(vs, QAPI_EVENT_VNC_DISCONNECTED);
Luiz Capitulino0d72f3d2010-01-14 14:50:58 -02001045
Corentin Chary5d418e32010-05-19 09:24:07 +02001046 buffer_free(&vs->input);
1047 buffer_free(&vs->output);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001048#ifdef CONFIG_VNC_WS
1049 buffer_free(&vs->ws_input);
1050 buffer_free(&vs->ws_output);
1051#endif /* CONFIG_VNC_WS */
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02001052
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +02001053 qapi_free_VncClientInfo(vs->info);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02001054
Corentin Chary161c4f22010-05-19 09:24:08 +02001055 vnc_zlib_clear(vs);
Corentin Chary380282b2010-05-19 09:24:10 +02001056 vnc_tight_clear(vs);
Corentin Chary148954f2011-02-04 09:06:01 +01001057 vnc_zrle_clear(vs);
Corentin Chary161c4f22010-05-19 09:24:08 +02001058
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001059#ifdef CONFIG_VNC_TLS
1060 vnc_tls_client_cleanup(vs);
1061#endif /* CONFIG_VNC_TLS */
1062#ifdef CONFIG_VNC_SASL
1063 vnc_sasl_client_cleanup(vs);
1064#endif /* CONFIG_VNC_SASL */
1065 audio_del(vs);
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001066 vnc_release_modifiers(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001067
Tim Hardeck6fd8e792013-01-21 11:04:45 +01001068 if (vs->initialized) {
1069 QTAILQ_REMOVE(&vs->vd->clients, vs, next);
1070 qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
1071 }
Amit Shah41b4bef2010-02-05 16:34:05 +05301072
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01001073 if (vs->vd->lock_key_sync)
1074 qemu_remove_led_event_handler(vs->led);
Corentin Charybd023f92010-07-07 20:58:02 +02001075 vnc_unlock_output(vs);
1076
Corentin Charybd023f92010-07-07 20:58:02 +02001077 qemu_mutex_destroy(&vs->output_mutex);
Tim Hardeck6fd8e792013-01-21 11:04:45 +01001078 if (vs->bh != NULL) {
1079 qemu_bh_delete(vs->bh);
1080 }
Corentin Chary175b2a62012-03-14 07:58:47 +01001081 buffer_free(&vs->jobs_buffer);
Corentin Chary175b2a62012-03-14 07:58:47 +01001082
Corentin Chary7d964c92011-02-04 09:05:56 +01001083 for (i = 0; i < VNC_STAT_ROWS; ++i) {
Anthony Liguori7267c092011-08-20 22:09:37 -05001084 g_free(vs->lossy_rect[i]);
Corentin Chary7d964c92011-02-04 09:05:56 +01001085 }
Anthony Liguori7267c092011-08-20 22:09:37 -05001086 g_free(vs->lossy_rect);
1087 g_free(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001088}
aliguori2f9606b2009-03-06 20:27:28 +00001089
1090int vnc_client_io_error(VncState *vs, int ret, int last_errno)
bellard24236862006-04-30 21:28:36 +00001091{
1092 if (ret == 0 || ret == -1) {
balrogea01e5f2008-04-24 23:40:55 +00001093 if (ret == -1) {
1094 switch (last_errno) {
1095 case EINTR:
1096 case EAGAIN:
1097#ifdef _WIN32
1098 case WSAEWOULDBLOCK:
1099#endif
1100 return 0;
1101 default:
1102 break;
1103 }
1104 }
bellard24236862006-04-30 21:28:36 +00001105
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001106 VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
1107 ret, ret < 0 ? last_errno : 0);
1108 vnc_disconnect_start(vs);
aliguori6baebed2009-03-20 15:59:14 +00001109
aliguori28a76be2009-03-06 20:27:40 +00001110 return 0;
bellard24236862006-04-30 21:28:36 +00001111 }
1112 return ret;
1113}
1114
aliguori5fb6c7a2009-03-06 20:27:23 +00001115
1116void vnc_client_error(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001117{
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001118 VNC_DEBUG("Closing down client sock: protocol error\n");
1119 vnc_disconnect_start(vs);
bellard24236862006-04-30 21:28:36 +00001120}
1121
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001122#ifdef CONFIG_VNC_TLS
1123static long vnc_client_write_tls(gnutls_session_t *session,
1124 const uint8_t *data,
1125 size_t datalen)
1126{
1127 long ret = gnutls_write(*session, data, datalen);
1128 if (ret < 0) {
1129 if (ret == GNUTLS_E_AGAIN) {
1130 errno = EAGAIN;
1131 } else {
1132 errno = EIO;
1133 }
1134 ret = -1;
1135 }
1136 return ret;
1137}
1138#endif /* CONFIG_VNC_TLS */
aliguori2f9606b2009-03-06 20:27:28 +00001139
1140/*
1141 * Called to write a chunk of data to the client socket. The data may
1142 * be the raw data, or may have already been encoded by SASL.
1143 * The data will be written either straight onto the socket, or
1144 * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1145 *
1146 * NB, it is theoretically possible to have 2 layers of encryption,
1147 * both SASL, and this TLS layer. It is highly unlikely in practice
1148 * though, since SASL encryption will typically be a no-op if TLS
1149 * is active
1150 *
1151 * Returns the number of bytes written, which may be less than
1152 * the requested 'datalen' if the socket would block. Returns
1153 * -1 on error, and disconnects the client socket.
1154 */
1155long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001156{
bellardceb5caa2006-05-03 21:18:59 +00001157 long ret;
blueswir1eb38c522008-09-06 17:47:39 +00001158#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +00001159 if (vs->tls.session) {
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001160 ret = vnc_client_write_tls(&vs->tls.session, data, datalen);
1161 } else {
1162#ifdef CONFIG_VNC_WS
1163 if (vs->ws_tls.session) {
1164 ret = vnc_client_write_tls(&vs->ws_tls.session, data, datalen);
1165 } else
1166#endif /* CONFIG_VNC_WS */
ths8d5d2d42007-08-25 01:37:51 +00001167#endif /* CONFIG_VNC_TLS */
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001168 {
1169 ret = send(vs->csock, (const void *)data, datalen, 0);
1170 }
1171#ifdef CONFIG_VNC_TLS
1172 }
1173#endif /* CONFIG_VNC_TLS */
aliguori23decc82009-03-20 15:59:18 +00001174 VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +00001175 return vnc_client_io_error(vs, ret, socket_error());
1176}
1177
1178
1179/*
1180 * Called to write buffered data to the client socket, when not
1181 * using any SASL SSF encryption layers. Will write as much data
1182 * as possible without blocking. If all buffered data is written,
1183 * will switch the FD poll() handler back to read monitoring.
1184 *
1185 * Returns the number of bytes written, which may be less than
1186 * the buffered output data if the socket would block. Returns
1187 * -1 on error, and disconnects the client socket.
1188 */
1189static long vnc_client_write_plain(VncState *vs)
1190{
1191 long ret;
1192
1193#ifdef CONFIG_VNC_SASL
aliguori23decc82009-03-20 15:59:18 +00001194 VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
aliguori2f9606b2009-03-06 20:27:28 +00001195 vs->output.buffer, vs->output.capacity, vs->output.offset,
1196 vs->sasl.waitWriteSSF);
1197
1198 if (vs->sasl.conn &&
1199 vs->sasl.runSSF &&
1200 vs->sasl.waitWriteSSF) {
1201 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
1202 if (ret)
1203 vs->sasl.waitWriteSSF -= ret;
1204 } else
1205#endif /* CONFIG_VNC_SASL */
1206 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
bellard24236862006-04-30 21:28:36 +00001207 if (!ret)
aliguori2f9606b2009-03-06 20:27:28 +00001208 return 0;
bellard24236862006-04-30 21:28:36 +00001209
Tim Hardeck32ed2682013-01-21 11:04:43 +01001210 buffer_advance(&vs->output, ret);
bellard24236862006-04-30 21:28:36 +00001211
1212 if (vs->output.offset == 0) {
aliguori28a76be2009-03-06 20:27:40 +00001213 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00001214 }
aliguori2f9606b2009-03-06 20:27:28 +00001215
1216 return ret;
1217}
1218
1219
1220/*
1221 * First function called whenever there is data to be written to
1222 * the client socket. Will delegate actual work according to whether
1223 * SASL SSF layers are enabled (thus requiring encryption calls)
1224 */
Corentin Charybd023f92010-07-07 20:58:02 +02001225static void vnc_client_write_locked(void *opaque)
aliguori2f9606b2009-03-06 20:27:28 +00001226{
aliguori2f9606b2009-03-06 20:27:28 +00001227 VncState *vs = opaque;
1228
1229#ifdef CONFIG_VNC_SASL
1230 if (vs->sasl.conn &&
1231 vs->sasl.runSSF &&
Blue Swirl9678d952010-04-25 18:35:52 +00001232 !vs->sasl.waitWriteSSF) {
1233 vnc_client_write_sasl(vs);
1234 } else
aliguori2f9606b2009-03-06 20:27:28 +00001235#endif /* CONFIG_VNC_SASL */
Tim Hardeck7536ee42013-01-21 11:04:44 +01001236 {
1237#ifdef CONFIG_VNC_WS
1238 if (vs->encode_ws) {
1239 vnc_client_write_ws(vs);
1240 } else
1241#endif /* CONFIG_VNC_WS */
1242 {
1243 vnc_client_write_plain(vs);
1244 }
1245 }
bellard24236862006-04-30 21:28:36 +00001246}
1247
Corentin Charybd023f92010-07-07 20:58:02 +02001248void vnc_client_write(void *opaque)
1249{
1250 VncState *vs = opaque;
1251
1252 vnc_lock_output(vs);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001253 if (vs->output.offset
1254#ifdef CONFIG_VNC_WS
1255 || vs->ws_output.offset
1256#endif
1257 ) {
Corentin Charybd023f92010-07-07 20:58:02 +02001258 vnc_client_write_locked(opaque);
Yoshiaki Tamuraac711032010-08-20 19:10:41 +09001259 } else if (vs->csock != -1) {
Corentin Charybd023f92010-07-07 20:58:02 +02001260 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
1261 }
1262 vnc_unlock_output(vs);
1263}
1264
aliguori5fb6c7a2009-03-06 20:27:23 +00001265void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
bellard24236862006-04-30 21:28:36 +00001266{
1267 vs->read_handler = func;
1268 vs->read_handler_expect = expecting;
1269}
1270
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001271#ifdef CONFIG_VNC_TLS
1272static long vnc_client_read_tls(gnutls_session_t *session, uint8_t *data,
1273 size_t datalen)
1274{
1275 long ret = gnutls_read(*session, data, datalen);
1276 if (ret < 0) {
1277 if (ret == GNUTLS_E_AGAIN) {
1278 errno = EAGAIN;
1279 } else {
1280 errno = EIO;
1281 }
1282 ret = -1;
1283 }
1284 return ret;
1285}
1286#endif /* CONFIG_VNC_TLS */
aliguori2f9606b2009-03-06 20:27:28 +00001287
1288/*
1289 * Called to read a chunk of data from the client socket. The data may
1290 * be the raw data, or may need to be further decoded by SASL.
1291 * The data will be read either straight from to the socket, or
1292 * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1293 *
1294 * NB, it is theoretically possible to have 2 layers of encryption,
1295 * both SASL, and this TLS layer. It is highly unlikely in practice
1296 * though, since SASL encryption will typically be a no-op if TLS
1297 * is active
1298 *
1299 * Returns the number of bytes read, which may be less than
1300 * the requested 'datalen' if the socket would block. Returns
1301 * -1 on error, and disconnects the client socket.
1302 */
1303long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001304{
bellardceb5caa2006-05-03 21:18:59 +00001305 long ret;
blueswir1eb38c522008-09-06 17:47:39 +00001306#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +00001307 if (vs->tls.session) {
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001308 ret = vnc_client_read_tls(&vs->tls.session, data, datalen);
1309 } else {
1310#ifdef CONFIG_VNC_WS
1311 if (vs->ws_tls.session) {
1312 ret = vnc_client_read_tls(&vs->ws_tls.session, data, datalen);
1313 } else
1314#endif /* CONFIG_VNC_WS */
ths8d5d2d42007-08-25 01:37:51 +00001315#endif /* CONFIG_VNC_TLS */
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001316 {
1317 ret = qemu_recv(vs->csock, data, datalen, 0);
1318 }
1319#ifdef CONFIG_VNC_TLS
1320 }
1321#endif /* CONFIG_VNC_TLS */
aliguori23decc82009-03-20 15:59:18 +00001322 VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +00001323 return vnc_client_io_error(vs, ret, socket_error());
1324}
1325
1326
1327/*
1328 * Called to read data from the client socket to the input buffer,
1329 * when not using any SASL SSF encryption layers. Will read as much
1330 * data as possible without blocking.
1331 *
1332 * Returns the number of bytes read. Returns -1 on error, and
1333 * disconnects the client socket.
1334 */
1335static long vnc_client_read_plain(VncState *vs)
1336{
1337 int ret;
aliguori23decc82009-03-20 15:59:18 +00001338 VNC_DEBUG("Read plain %p size %zd offset %zd\n",
aliguori2f9606b2009-03-06 20:27:28 +00001339 vs->input.buffer, vs->input.capacity, vs->input.offset);
1340 buffer_reserve(&vs->input, 4096);
1341 ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
1342 if (!ret)
1343 return 0;
1344 vs->input.offset += ret;
1345 return ret;
1346}
1347
Corentin Chary175b2a62012-03-14 07:58:47 +01001348static void vnc_jobs_bh(void *opaque)
1349{
1350 VncState *vs = opaque;
1351
1352 vnc_jobs_consume_buffer(vs);
1353}
aliguori2f9606b2009-03-06 20:27:28 +00001354
1355/*
1356 * First function called whenever there is more data to be read from
1357 * the client socket. Will delegate actual work according to whether
1358 * SASL SSF layers are enabled (thus requiring decryption calls)
1359 */
1360void vnc_client_read(void *opaque)
1361{
1362 VncState *vs = opaque;
1363 long ret;
1364
1365#ifdef CONFIG_VNC_SASL
1366 if (vs->sasl.conn && vs->sasl.runSSF)
1367 ret = vnc_client_read_sasl(vs);
1368 else
1369#endif /* CONFIG_VNC_SASL */
Tim Hardeck7536ee42013-01-21 11:04:44 +01001370#ifdef CONFIG_VNC_WS
1371 if (vs->encode_ws) {
1372 ret = vnc_client_read_ws(vs);
1373 if (ret == -1) {
1374 vnc_disconnect_start(vs);
1375 return;
1376 } else if (ret == -2) {
1377 vnc_client_error(vs);
1378 return;
1379 }
1380 } else
1381#endif /* CONFIG_VNC_WS */
1382 {
aliguori2f9606b2009-03-06 20:27:28 +00001383 ret = vnc_client_read_plain(vs);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001384 }
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001385 if (!ret) {
1386 if (vs->csock == -1)
1387 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001388 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001389 }
bellard24236862006-04-30 21:28:36 +00001390
bellard24236862006-04-30 21:28:36 +00001391 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
aliguori28a76be2009-03-06 20:27:40 +00001392 size_t len = vs->read_handler_expect;
1393 int ret;
bellard24236862006-04-30 21:28:36 +00001394
aliguori28a76be2009-03-06 20:27:40 +00001395 ret = vs->read_handler(vs, vs->input.buffer, len);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001396 if (vs->csock == -1) {
1397 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001398 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001399 }
bellard24236862006-04-30 21:28:36 +00001400
aliguori28a76be2009-03-06 20:27:40 +00001401 if (!ret) {
Tim Hardeck32ed2682013-01-21 11:04:43 +01001402 buffer_advance(&vs->input, len);
aliguori28a76be2009-03-06 20:27:40 +00001403 } else {
1404 vs->read_handler_expect = ret;
1405 }
bellard24236862006-04-30 21:28:36 +00001406 }
1407}
1408
aliguori5fb6c7a2009-03-06 20:27:23 +00001409void vnc_write(VncState *vs, const void *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001410{
1411 buffer_reserve(&vs->output, len);
1412
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001413 if (vs->csock != -1 && buffer_empty(&vs->output)) {
aliguori28a76be2009-03-06 20:27:40 +00001414 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
bellard24236862006-04-30 21:28:36 +00001415 }
1416
1417 buffer_append(&vs->output, data, len);
1418}
1419
aliguori5fb6c7a2009-03-06 20:27:23 +00001420void vnc_write_s32(VncState *vs, int32_t value)
bellard24236862006-04-30 21:28:36 +00001421{
1422 vnc_write_u32(vs, *(uint32_t *)&value);
1423}
1424
aliguori5fb6c7a2009-03-06 20:27:23 +00001425void vnc_write_u32(VncState *vs, uint32_t value)
bellard24236862006-04-30 21:28:36 +00001426{
1427 uint8_t buf[4];
1428
1429 buf[0] = (value >> 24) & 0xFF;
1430 buf[1] = (value >> 16) & 0xFF;
1431 buf[2] = (value >> 8) & 0xFF;
1432 buf[3] = value & 0xFF;
1433
1434 vnc_write(vs, buf, 4);
1435}
1436
aliguori5fb6c7a2009-03-06 20:27:23 +00001437void vnc_write_u16(VncState *vs, uint16_t value)
bellard24236862006-04-30 21:28:36 +00001438{
bellard64f5a132006-08-24 20:36:44 +00001439 uint8_t buf[2];
bellard24236862006-04-30 21:28:36 +00001440
1441 buf[0] = (value >> 8) & 0xFF;
1442 buf[1] = value & 0xFF;
1443
1444 vnc_write(vs, buf, 2);
1445}
1446
aliguori5fb6c7a2009-03-06 20:27:23 +00001447void vnc_write_u8(VncState *vs, uint8_t value)
bellard24236862006-04-30 21:28:36 +00001448{
1449 vnc_write(vs, (char *)&value, 1);
1450}
1451
aliguori5fb6c7a2009-03-06 20:27:23 +00001452void vnc_flush(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001453{
Corentin Charybd023f92010-07-07 20:58:02 +02001454 vnc_lock_output(vs);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001455 if (vs->csock != -1 && (vs->output.offset
1456#ifdef CONFIG_VNC_WS
1457 || vs->ws_output.offset
1458#endif
1459 )) {
Corentin Charybd023f92010-07-07 20:58:02 +02001460 vnc_client_write_locked(vs);
1461 }
1462 vnc_unlock_output(vs);
bellard24236862006-04-30 21:28:36 +00001463}
1464
Blue Swirl71a8cde2012-10-28 11:04:48 +00001465static uint8_t read_u8(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001466{
1467 return data[offset];
1468}
1469
Blue Swirl71a8cde2012-10-28 11:04:48 +00001470static uint16_t read_u16(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001471{
1472 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
1473}
1474
Blue Swirl71a8cde2012-10-28 11:04:48 +00001475static int32_t read_s32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001476{
1477 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001478 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001479}
1480
aliguori5fb6c7a2009-03-06 20:27:23 +00001481uint32_t read_u32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001482{
1483 return ((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001484 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001485}
1486
ths60fe76f2007-12-16 03:02:09 +00001487static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
bellard24236862006-04-30 21:28:36 +00001488{
1489}
1490
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001491static void check_pointer_type_change(Notifier *notifier, void *data)
bellard564c3372007-02-05 20:14:10 +00001492{
Anthony Liguori37c34d92010-03-10 09:38:29 -06001493 VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001494 int absolute = qemu_input_is_absolute();
Anthony Liguori37c34d92010-03-10 09:38:29 -06001495
aliguori29fa4ed2009-02-02 15:58:29 +00001496 if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
Corentin Charybd023f92010-07-07 20:58:02 +02001497 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001498 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
aliguori28a76be2009-03-06 20:27:40 +00001499 vnc_write_u8(vs, 0);
1500 vnc_write_u16(vs, 1);
1501 vnc_framebuffer_update(vs, absolute, 0,
Peter Lievenbea60dd2014-06-30 10:57:51 +02001502 pixman_image_get_width(vs->vd->server),
1503 pixman_image_get_height(vs->vd->server),
aliguori29fa4ed2009-02-02 15:58:29 +00001504 VNC_ENCODING_POINTER_TYPE_CHANGE);
Corentin Charybd023f92010-07-07 20:58:02 +02001505 vnc_unlock_output(vs);
aliguori28a76be2009-03-06 20:27:40 +00001506 vnc_flush(vs);
bellard564c3372007-02-05 20:14:10 +00001507 }
1508 vs->absolute = absolute;
1509}
1510
bellard24236862006-04-30 21:28:36 +00001511static void pointer_event(VncState *vs, int button_mask, int x, int y)
1512{
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001513 static uint32_t bmap[INPUT_BUTTON_MAX] = {
1514 [INPUT_BUTTON_LEFT] = 0x01,
1515 [INPUT_BUTTON_MIDDLE] = 0x02,
1516 [INPUT_BUTTON_RIGHT] = 0x04,
1517 [INPUT_BUTTON_WHEEL_UP] = 0x08,
1518 [INPUT_BUTTON_WHEEL_DOWN] = 0x10,
1519 };
1520 QemuConsole *con = vs->vd->dcl.con;
Peter Lievenbea60dd2014-06-30 10:57:51 +02001521 int width = pixman_image_get_width(vs->vd->server);
1522 int height = pixman_image_get_height(vs->vd->server);
bellard24236862006-04-30 21:28:36 +00001523
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001524 if (vs->last_bmask != button_mask) {
1525 qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
1526 vs->last_bmask = button_mask;
1527 }
bellard564c3372007-02-05 20:14:10 +00001528
1529 if (vs->absolute) {
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001530 qemu_input_queue_abs(con, INPUT_AXIS_X, x, width);
1531 qemu_input_queue_abs(con, INPUT_AXIS_Y, y, height);
aliguori29fa4ed2009-02-02 15:58:29 +00001532 } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001533 qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF);
1534 qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF);
bellard24236862006-04-30 21:28:36 +00001535 } else {
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001536 if (vs->last_x != -1) {
1537 qemu_input_queue_rel(con, INPUT_AXIS_X, x - vs->last_x);
1538 qemu_input_queue_rel(con, INPUT_AXIS_Y, y - vs->last_y);
1539 }
aliguori28a76be2009-03-06 20:27:40 +00001540 vs->last_x = x;
1541 vs->last_y = y;
bellard24236862006-04-30 21:28:36 +00001542 }
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001543 qemu_input_event_sync();
bellard24236862006-04-30 21:28:36 +00001544}
1545
bellard64f5a132006-08-24 20:36:44 +00001546static void reset_keys(VncState *vs)
1547{
1548 int i;
1549 for(i = 0; i < 256; i++) {
1550 if (vs->modifiers_state[i]) {
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001551 qemu_input_event_send_key_number(vs->vd->dcl.con, i, false);
bellard64f5a132006-08-24 20:36:44 +00001552 vs->modifiers_state[i] = 0;
1553 }
1554 }
1555}
1556
balroga528b802007-10-30 22:38:53 +00001557static void press_key(VncState *vs, int keysym)
1558{
Samuel Thibault44bb61c2010-02-28 21:03:00 +01001559 int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001560 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
Gerd Hoffmann2deb4ac2014-06-02 13:15:05 +02001561 qemu_input_event_send_key_delay(0);
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001562 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
Gerd Hoffmann2deb4ac2014-06-02 13:15:05 +02001563 qemu_input_event_send_key_delay(0);
balroga528b802007-10-30 22:38:53 +00001564}
1565
Lei Liab99e5c2013-04-25 13:29:10 +08001566static int current_led_state(VncState *vs)
1567{
1568 int ledstate = 0;
1569
1570 if (vs->modifiers_state[0x46]) {
1571 ledstate |= QEMU_SCROLL_LOCK_LED;
1572 }
1573 if (vs->modifiers_state[0x45]) {
1574 ledstate |= QEMU_NUM_LOCK_LED;
1575 }
1576 if (vs->modifiers_state[0x3a]) {
1577 ledstate |= QEMU_CAPS_LOCK_LED;
1578 }
1579
1580 return ledstate;
1581}
1582
1583static void vnc_led_state_change(VncState *vs)
1584{
1585 int ledstate = 0;
1586
1587 if (!vnc_has_feature(vs, VNC_FEATURE_LED_STATE)) {
1588 return;
1589 }
1590
1591 ledstate = current_led_state(vs);
1592 vnc_lock_output(vs);
1593 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1594 vnc_write_u8(vs, 0);
1595 vnc_write_u16(vs, 1);
1596 vnc_framebuffer_update(vs, 0, 0, 1, 1, VNC_ENCODING_LED_STATE);
1597 vnc_write_u8(vs, ledstate);
1598 vnc_unlock_output(vs);
1599 vnc_flush(vs);
1600}
1601
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001602static void kbd_leds(void *opaque, int ledstate)
1603{
1604 VncState *vs = opaque;
Lei Li96f3d172013-04-25 13:29:09 +08001605 int caps, num, scr;
Lei Li1483adc2013-05-15 16:20:40 +08001606 bool has_changed = (ledstate != current_led_state(vs));
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001607
Gerd Hoffmann40066172014-05-21 13:18:20 +02001608 trace_vnc_key_guest_leds((ledstate & QEMU_CAPS_LOCK_LED),
1609 (ledstate & QEMU_NUM_LOCK_LED),
1610 (ledstate & QEMU_SCROLL_LOCK_LED));
1611
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001612 caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
1613 num = ledstate & QEMU_NUM_LOCK_LED ? 1 : 0;
Lei Li96f3d172013-04-25 13:29:09 +08001614 scr = ledstate & QEMU_SCROLL_LOCK_LED ? 1 : 0;
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001615
1616 if (vs->modifiers_state[0x3a] != caps) {
1617 vs->modifiers_state[0x3a] = caps;
1618 }
1619 if (vs->modifiers_state[0x45] != num) {
1620 vs->modifiers_state[0x45] = num;
1621 }
Lei Li96f3d172013-04-25 13:29:09 +08001622 if (vs->modifiers_state[0x46] != scr) {
1623 vs->modifiers_state[0x46] = scr;
1624 }
Lei Liab99e5c2013-04-25 13:29:10 +08001625
1626 /* Sending the current led state message to the client */
Lei Li1483adc2013-05-15 16:20:40 +08001627 if (has_changed) {
Lei Liab99e5c2013-04-25 13:29:10 +08001628 vnc_led_state_change(vs);
1629 }
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001630}
1631
aliguori9ca313a2008-08-23 23:27:37 +00001632static void do_key_event(VncState *vs, int down, int keycode, int sym)
bellard24236862006-04-30 21:28:36 +00001633{
bellard64f5a132006-08-24 20:36:44 +00001634 /* QEMU console switch */
1635 switch(keycode) {
1636 case 0x2a: /* Left Shift */
1637 case 0x36: /* Right Shift */
1638 case 0x1d: /* Left CTRL */
1639 case 0x9d: /* Right CTRL */
1640 case 0x38: /* Left ALT */
1641 case 0xb8: /* Right ALT */
1642 if (down)
1643 vs->modifiers_state[keycode] = 1;
1644 else
1645 vs->modifiers_state[keycode] = 0;
1646 break;
ths5fafdf22007-09-16 21:08:06 +00001647 case 0x02 ... 0x0a: /* '1' to '9' keys */
bellard64f5a132006-08-24 20:36:44 +00001648 if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1649 /* Reset the modifiers sent to the current console */
1650 reset_keys(vs);
1651 console_select(keycode - 0x02);
1652 return;
1653 }
1654 break;
aliguori28a76be2009-03-06 20:27:40 +00001655 case 0x3a: /* CapsLock */
1656 case 0x45: /* NumLock */
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001657 if (down)
balroga528b802007-10-30 22:38:53 +00001658 vs->modifiers_state[keycode] ^= 1;
1659 break;
1660 }
1661
Lei Lie7b2aac2013-04-25 13:29:11 +08001662 /* Turn off the lock state sync logic if the client support the led
1663 state extension.
1664 */
Gerd Hoffmann98920882011-01-14 10:56:54 +01001665 if (down && vs->vd->lock_key_sync &&
Lei Lie7b2aac2013-04-25 13:29:11 +08001666 !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01001667 keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
balroga528b802007-10-30 22:38:53 +00001668 /* If the numlock state needs to change then simulate an additional
1669 keypress before sending this one. This will happen if the user
1670 toggles numlock away from the VNC window.
1671 */
aliguori753b4052009-02-16 14:59:30 +00001672 if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
balroga528b802007-10-30 22:38:53 +00001673 if (!vs->modifiers_state[0x45]) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001674 trace_vnc_key_sync_numlock(true);
balroga528b802007-10-30 22:38:53 +00001675 vs->modifiers_state[0x45] = 1;
1676 press_key(vs, 0xff7f);
1677 }
1678 } else {
1679 if (vs->modifiers_state[0x45]) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001680 trace_vnc_key_sync_numlock(false);
balroga528b802007-10-30 22:38:53 +00001681 vs->modifiers_state[0x45] = 0;
1682 press_key(vs, 0xff7f);
1683 }
1684 }
bellard64f5a132006-08-24 20:36:44 +00001685 }
bellard24236862006-04-30 21:28:36 +00001686
Gerd Hoffmann98920882011-01-14 10:56:54 +01001687 if (down && vs->vd->lock_key_sync &&
Lei Lie7b2aac2013-04-25 13:29:11 +08001688 !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01001689 ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001690 /* If the capslock state needs to change then simulate an additional
1691 keypress before sending this one. This will happen if the user
1692 toggles capslock away from the VNC window.
1693 */
1694 int uppercase = !!(sym >= 'A' && sym <= 'Z');
1695 int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
1696 int capslock = !!(vs->modifiers_state[0x3a]);
1697 if (capslock) {
1698 if (uppercase == shift) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001699 trace_vnc_key_sync_capslock(false);
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001700 vs->modifiers_state[0x3a] = 0;
1701 press_key(vs, 0xffe5);
1702 }
1703 } else {
1704 if (uppercase != shift) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001705 trace_vnc_key_sync_capslock(true);
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001706 vs->modifiers_state[0x3a] = 1;
1707 press_key(vs, 0xffe5);
1708 }
1709 }
1710 }
1711
Gerd Hoffmann81c0d5a2013-03-14 14:27:08 +01001712 if (qemu_console_is_graphic(NULL)) {
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001713 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
bellard64f5a132006-08-24 20:36:44 +00001714 } else {
Gerd Hoffmanne26437c2011-11-08 10:02:16 +01001715 bool numlock = vs->modifiers_state[0x45];
1716 bool control = (vs->modifiers_state[0x1d] ||
1717 vs->modifiers_state[0x9d]);
bellard64f5a132006-08-24 20:36:44 +00001718 /* QEMU console emulation */
1719 if (down) {
1720 switch (keycode) {
1721 case 0x2a: /* Left Shift */
1722 case 0x36: /* Right Shift */
1723 case 0x1d: /* Left CTRL */
1724 case 0x9d: /* Right CTRL */
1725 case 0x38: /* Left ALT */
1726 case 0xb8: /* Right ALT */
1727 break;
1728 case 0xc8:
1729 kbd_put_keysym(QEMU_KEY_UP);
1730 break;
1731 case 0xd0:
1732 kbd_put_keysym(QEMU_KEY_DOWN);
1733 break;
1734 case 0xcb:
1735 kbd_put_keysym(QEMU_KEY_LEFT);
1736 break;
1737 case 0xcd:
1738 kbd_put_keysym(QEMU_KEY_RIGHT);
1739 break;
1740 case 0xd3:
1741 kbd_put_keysym(QEMU_KEY_DELETE);
1742 break;
1743 case 0xc7:
1744 kbd_put_keysym(QEMU_KEY_HOME);
1745 break;
1746 case 0xcf:
1747 kbd_put_keysym(QEMU_KEY_END);
1748 break;
1749 case 0xc9:
1750 kbd_put_keysym(QEMU_KEY_PAGEUP);
1751 break;
1752 case 0xd1:
1753 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1754 break;
Gerd Hoffmannbb0a18e2009-06-11 11:32:14 +02001755
1756 case 0x47:
1757 kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
1758 break;
1759 case 0x48:
1760 kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
1761 break;
1762 case 0x49:
1763 kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
1764 break;
1765 case 0x4b:
1766 kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
1767 break;
1768 case 0x4c:
1769 kbd_put_keysym('5');
1770 break;
1771 case 0x4d:
1772 kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
1773 break;
1774 case 0x4f:
1775 kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
1776 break;
1777 case 0x50:
1778 kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
1779 break;
1780 case 0x51:
1781 kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
1782 break;
1783 case 0x52:
1784 kbd_put_keysym('0');
1785 break;
1786 case 0x53:
1787 kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
1788 break;
1789
1790 case 0xb5:
1791 kbd_put_keysym('/');
1792 break;
1793 case 0x37:
1794 kbd_put_keysym('*');
1795 break;
1796 case 0x4a:
1797 kbd_put_keysym('-');
1798 break;
1799 case 0x4e:
1800 kbd_put_keysym('+');
1801 break;
1802 case 0x9c:
1803 kbd_put_keysym('\n');
1804 break;
1805
bellard64f5a132006-08-24 20:36:44 +00001806 default:
Gerd Hoffmanne26437c2011-11-08 10:02:16 +01001807 if (control) {
1808 kbd_put_keysym(sym & 0x1f);
1809 } else {
1810 kbd_put_keysym(sym);
1811 }
bellard64f5a132006-08-24 20:36:44 +00001812 break;
1813 }
1814 }
1815 }
bellard24236862006-04-30 21:28:36 +00001816}
1817
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001818static void vnc_release_modifiers(VncState *vs)
1819{
1820 static const int keycodes[] = {
1821 /* shift, control, alt keys, both left & right */
1822 0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8,
1823 };
1824 int i, keycode;
1825
Gerd Hoffmann81c0d5a2013-03-14 14:27:08 +01001826 if (!qemu_console_is_graphic(NULL)) {
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001827 return;
1828 }
1829 for (i = 0; i < ARRAY_SIZE(keycodes); i++) {
1830 keycode = keycodes[i];
1831 if (!vs->modifiers_state[keycode]) {
1832 continue;
1833 }
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001834 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001835 }
1836}
1837
Gerd Hoffmann40066172014-05-21 13:18:20 +02001838static const char *code2name(int keycode)
1839{
1840 return QKeyCode_lookup[qemu_input_key_number_to_qcode(keycode)];
1841}
1842
bellardbdbd7672006-05-01 21:44:22 +00001843static void key_event(VncState *vs, int down, uint32_t sym)
1844{
aliguori9ca313a2008-08-23 23:27:37 +00001845 int keycode;
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001846 int lsym = sym;
aliguori9ca313a2008-08-23 23:27:37 +00001847
Gerd Hoffmann81c0d5a2013-03-14 14:27:08 +01001848 if (lsym >= 'A' && lsym <= 'Z' && qemu_console_is_graphic(NULL)) {
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001849 lsym = lsym - 'A' + 'a';
1850 }
aliguori9ca313a2008-08-23 23:27:37 +00001851
Samuel Thibault44bb61c2010-02-28 21:03:00 +01001852 keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
Gerd Hoffmann40066172014-05-21 13:18:20 +02001853 trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
aliguori9ca313a2008-08-23 23:27:37 +00001854 do_key_event(vs, down, keycode, sym);
1855}
1856
1857static void ext_key_event(VncState *vs, int down,
1858 uint32_t sym, uint16_t keycode)
1859{
1860 /* if the user specifies a keyboard layout, always use it */
Gerd Hoffmann40066172014-05-21 13:18:20 +02001861 if (keyboard_layout) {
aliguori9ca313a2008-08-23 23:27:37 +00001862 key_event(vs, down, sym);
Gerd Hoffmann40066172014-05-21 13:18:20 +02001863 } else {
1864 trace_vnc_key_event_ext(down, sym, keycode, code2name(keycode));
aliguori9ca313a2008-08-23 23:27:37 +00001865 do_key_event(vs, down, keycode, sym);
Gerd Hoffmann40066172014-05-21 13:18:20 +02001866 }
bellardbdbd7672006-05-01 21:44:22 +00001867}
1868
bellard24236862006-04-30 21:28:36 +00001869static void framebuffer_update_request(VncState *vs, int incremental,
Peter Lievenbea60dd2014-06-30 10:57:51 +02001870 int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +00001871{
Peter Lievenbea60dd2014-06-30 10:57:51 +02001872 int width = pixman_image_get_width(vs->vd->server);
1873 int height = pixman_image_get_height(vs->vd->server);
thscf2d3852007-04-29 01:53:20 +00001874
bellard24236862006-04-30 21:28:36 +00001875 vs->need_update = 1;
Peter Lievenbea60dd2014-06-30 10:57:51 +02001876
1877 if (incremental) {
1878 return;
bellard24236862006-04-30 21:28:36 +00001879 }
Peter Lievenbea60dd2014-06-30 10:57:51 +02001880
Stephan Kulow07535a82014-07-23 16:03:14 +02001881 vs->force_update = 1;
Peter Lievenbea60dd2014-06-30 10:57:51 +02001882 vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h);
bellard24236862006-04-30 21:28:36 +00001883}
1884
aliguori9ca313a2008-08-23 23:27:37 +00001885static void send_ext_key_event_ack(VncState *vs)
1886{
Corentin Charybd023f92010-07-07 20:58:02 +02001887 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001888 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
aliguori9ca313a2008-08-23 23:27:37 +00001889 vnc_write_u8(vs, 0);
1890 vnc_write_u16(vs, 1);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01001891 vnc_framebuffer_update(vs, 0, 0,
Peter Lievenbea60dd2014-06-30 10:57:51 +02001892 pixman_image_get_width(vs->vd->server),
1893 pixman_image_get_height(vs->vd->server),
aliguori29fa4ed2009-02-02 15:58:29 +00001894 VNC_ENCODING_EXT_KEY_EVENT);
Corentin Charybd023f92010-07-07 20:58:02 +02001895 vnc_unlock_output(vs);
aliguori9ca313a2008-08-23 23:27:37 +00001896 vnc_flush(vs);
1897}
1898
malc429a8ed2008-12-01 20:57:48 +00001899static void send_ext_audio_ack(VncState *vs)
1900{
Corentin Charybd023f92010-07-07 20:58:02 +02001901 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001902 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
malc429a8ed2008-12-01 20:57:48 +00001903 vnc_write_u8(vs, 0);
1904 vnc_write_u16(vs, 1);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01001905 vnc_framebuffer_update(vs, 0, 0,
Peter Lievenbea60dd2014-06-30 10:57:51 +02001906 pixman_image_get_width(vs->vd->server),
1907 pixman_image_get_height(vs->vd->server),
aliguori29fa4ed2009-02-02 15:58:29 +00001908 VNC_ENCODING_AUDIO);
Corentin Charybd023f92010-07-07 20:58:02 +02001909 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +00001910 vnc_flush(vs);
1911}
1912
bellard24236862006-04-30 21:28:36 +00001913static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1914{
1915 int i;
aliguori29fa4ed2009-02-02 15:58:29 +00001916 unsigned int enc = 0;
bellard24236862006-04-30 21:28:36 +00001917
aliguori29fa4ed2009-02-02 15:58:29 +00001918 vs->features = 0;
Corentin Charya9f20d32010-05-19 09:24:01 +02001919 vs->vnc_encoding = 0;
Corentin Charyd1af0e02010-07-07 20:57:59 +02001920 vs->tight.compression = 9;
1921 vs->tight.quality = -1; /* Lossless by default */
bellard564c3372007-02-05 20:14:10 +00001922 vs->absolute = -1;
bellard24236862006-04-30 21:28:36 +00001923
Corentin Chary8a0f0d02010-05-19 09:24:02 +02001924 /*
1925 * Start from the end because the encodings are sent in order of preference.
Dong Xu Wange5bed752011-11-22 18:06:24 +08001926 * This way the preferred encoding (first encoding defined in the array)
Corentin Chary8a0f0d02010-05-19 09:24:02 +02001927 * will be set at the end of the loop.
1928 */
bellard24236862006-04-30 21:28:36 +00001929 for (i = n_encodings - 1; i >= 0; i--) {
aliguori29fa4ed2009-02-02 15:58:29 +00001930 enc = encodings[i];
1931 switch (enc) {
1932 case VNC_ENCODING_RAW:
Corentin Charya9f20d32010-05-19 09:24:01 +02001933 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001934 break;
1935 case VNC_ENCODING_COPYRECT:
aliguori753b4052009-02-16 14:59:30 +00001936 vs->features |= VNC_FEATURE_COPYRECT_MASK;
aliguori29fa4ed2009-02-02 15:58:29 +00001937 break;
1938 case VNC_ENCODING_HEXTILE:
1939 vs->features |= VNC_FEATURE_HEXTILE_MASK;
Corentin Charya9f20d32010-05-19 09:24:01 +02001940 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001941 break;
Corentin Chary380282b2010-05-19 09:24:10 +02001942 case VNC_ENCODING_TIGHT:
1943 vs->features |= VNC_FEATURE_TIGHT_MASK;
1944 vs->vnc_encoding = enc;
1945 break;
Joel Martinfe3e7f22012-05-16 12:54:25 +00001946#ifdef CONFIG_VNC_PNG
Corentin Charyefe556a2010-07-07 20:57:56 +02001947 case VNC_ENCODING_TIGHT_PNG:
1948 vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
1949 vs->vnc_encoding = enc;
1950 break;
Joel Martinfe3e7f22012-05-16 12:54:25 +00001951#endif
aliguori059cef42009-02-02 15:58:54 +00001952 case VNC_ENCODING_ZLIB:
1953 vs->features |= VNC_FEATURE_ZLIB_MASK;
Corentin Charya9f20d32010-05-19 09:24:01 +02001954 vs->vnc_encoding = enc;
aliguori059cef42009-02-02 15:58:54 +00001955 break;
Corentin Chary148954f2011-02-04 09:06:01 +01001956 case VNC_ENCODING_ZRLE:
1957 vs->features |= VNC_FEATURE_ZRLE_MASK;
1958 vs->vnc_encoding = enc;
1959 break;
1960 case VNC_ENCODING_ZYWRLE:
1961 vs->features |= VNC_FEATURE_ZYWRLE_MASK;
1962 vs->vnc_encoding = enc;
1963 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001964 case VNC_ENCODING_DESKTOPRESIZE:
1965 vs->features |= VNC_FEATURE_RESIZE_MASK;
1966 break;
1967 case VNC_ENCODING_POINTER_TYPE_CHANGE:
1968 vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
1969 break;
Gerd Hoffmannd467b672010-05-21 11:54:34 +02001970 case VNC_ENCODING_RICH_CURSOR:
1971 vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
1972 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001973 case VNC_ENCODING_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00001974 send_ext_key_event_ack(vs);
1975 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001976 case VNC_ENCODING_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00001977 send_ext_audio_ack(vs);
1978 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001979 case VNC_ENCODING_WMVi:
1980 vs->features |= VNC_FEATURE_WMVI_MASK;
aliguorica4cca42008-09-15 16:05:16 +00001981 break;
Lei Liab99e5c2013-04-25 13:29:10 +08001982 case VNC_ENCODING_LED_STATE:
1983 vs->features |= VNC_FEATURE_LED_STATE_MASK;
1984 break;
aliguorifb437312009-02-02 15:58:43 +00001985 case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
Corentin Charyd1af0e02010-07-07 20:57:59 +02001986 vs->tight.compression = (enc & 0x0F);
aliguorifb437312009-02-02 15:58:43 +00001987 break;
1988 case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
Corentin Charyb31f5192011-02-04 09:05:54 +01001989 if (vs->vd->lossy) {
1990 vs->tight.quality = (enc & 0x0F);
1991 }
aliguorifb437312009-02-02 15:58:43 +00001992 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001993 default:
1994 VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
1995 break;
1996 }
bellard24236862006-04-30 21:28:36 +00001997 }
Gerd Hoffmann6356e472010-05-25 18:25:17 +02001998 vnc_desktop_resize(vs);
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001999 check_pointer_type_change(&vs->mouse_mode_notifier, NULL);
Lei Liab99e5c2013-04-25 13:29:10 +08002000 vnc_led_state_change(vs);
bellard24236862006-04-30 21:28:36 +00002001}
2002
aliguori6cec5482009-01-15 22:17:38 +00002003static void set_pixel_conversion(VncState *vs)
2004{
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002005 pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf);
2006
2007 if (fmt == VNC_SERVER_FB_FORMAT) {
aliguori6cec5482009-01-15 22:17:38 +00002008 vs->write_pixels = vnc_write_pixels_copy;
Corentin Chary70a45682010-05-03 14:31:34 +02002009 vnc_hextile_set_pixel_conversion(vs, 0);
aliguori6cec5482009-01-15 22:17:38 +00002010 } else {
2011 vs->write_pixels = vnc_write_pixels_generic;
Corentin Chary70a45682010-05-03 14:31:34 +02002012 vnc_hextile_set_pixel_conversion(vs, 1);
aliguori6cec5482009-01-15 22:17:38 +00002013 }
2014}
2015
bellard24236862006-04-30 21:28:36 +00002016static void set_pixel_format(VncState *vs,
aliguori28a76be2009-03-06 20:27:40 +00002017 int bits_per_pixel, int depth,
2018 int big_endian_flag, int true_color_flag,
2019 int red_max, int green_max, int blue_max,
2020 int red_shift, int green_shift, int blue_shift)
bellard24236862006-04-30 21:28:36 +00002021{
bellard35127792006-05-14 18:11:49 +00002022 if (!true_color_flag) {
aliguori28a76be2009-03-06 20:27:40 +00002023 vnc_client_error(vs);
bellard35127792006-05-14 18:11:49 +00002024 return;
2025 }
aliguori7eac3a82008-09-15 16:03:41 +00002026
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002027 vs->client_pf.rmax = red_max;
2028 vs->client_pf.rbits = hweight_long(red_max);
2029 vs->client_pf.rshift = red_shift;
2030 vs->client_pf.rmask = red_max << red_shift;
2031 vs->client_pf.gmax = green_max;
2032 vs->client_pf.gbits = hweight_long(green_max);
2033 vs->client_pf.gshift = green_shift;
2034 vs->client_pf.gmask = green_max << green_shift;
2035 vs->client_pf.bmax = blue_max;
2036 vs->client_pf.bbits = hweight_long(blue_max);
2037 vs->client_pf.bshift = blue_shift;
2038 vs->client_pf.bmask = blue_max << blue_shift;
2039 vs->client_pf.bits_per_pixel = bits_per_pixel;
2040 vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
2041 vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
2042 vs->client_be = big_endian_flag;
bellard24236862006-04-30 21:28:36 +00002043
aliguori6cec5482009-01-15 22:17:38 +00002044 set_pixel_conversion(vs);
bellard24236862006-04-30 21:28:36 +00002045
Gerd Hoffmann1dbfa002013-03-12 13:44:38 +01002046 graphic_hw_invalidate(NULL);
2047 graphic_hw_update(NULL);
bellard24236862006-04-30 21:28:36 +00002048}
2049
aliguorica4cca42008-09-15 16:05:16 +00002050static void pixel_format_message (VncState *vs) {
2051 char pad[3] = { 0, 0, 0 };
2052
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002053 vs->client_pf = qemu_default_pixelformat(32);
2054
2055 vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */
2056 vnc_write_u8(vs, vs->client_pf.depth); /* depth */
aliguorica4cca42008-09-15 16:05:16 +00002057
Juan Quintelae2542fe2009-07-27 16:13:06 +02002058#ifdef HOST_WORDS_BIGENDIAN
aliguorica4cca42008-09-15 16:05:16 +00002059 vnc_write_u8(vs, 1); /* big-endian-flag */
2060#else
2061 vnc_write_u8(vs, 0); /* big-endian-flag */
2062#endif
2063 vnc_write_u8(vs, 1); /* true-color-flag */
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002064 vnc_write_u16(vs, vs->client_pf.rmax); /* red-max */
2065 vnc_write_u16(vs, vs->client_pf.gmax); /* green-max */
2066 vnc_write_u16(vs, vs->client_pf.bmax); /* blue-max */
2067 vnc_write_u8(vs, vs->client_pf.rshift); /* red-shift */
2068 vnc_write_u8(vs, vs->client_pf.gshift); /* green-shift */
2069 vnc_write_u8(vs, vs->client_pf.bshift); /* blue-shift */
2070 vnc_write(vs, pad, 3); /* padding */
Corentin Chary70a45682010-05-03 14:31:34 +02002071
2072 vnc_hextile_set_pixel_conversion(vs, 0);
aliguorica4cca42008-09-15 16:05:16 +00002073 vs->write_pixels = vnc_write_pixels_copy;
aliguorica4cca42008-09-15 16:05:16 +00002074}
2075
aliguori753b4052009-02-16 14:59:30 +00002076static void vnc_colordepth(VncState *vs)
aliguori7eac3a82008-09-15 16:03:41 +00002077{
aliguori753b4052009-02-16 14:59:30 +00002078 if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
aliguorica4cca42008-09-15 16:05:16 +00002079 /* Sending a WMVi message to notify the client*/
Corentin Charybd023f92010-07-07 20:58:02 +02002080 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002081 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
aliguorica4cca42008-09-15 16:05:16 +00002082 vnc_write_u8(vs, 0);
2083 vnc_write_u16(vs, 1); /* number of rects */
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01002084 vnc_framebuffer_update(vs, 0, 0,
Peter Lievenbea60dd2014-06-30 10:57:51 +02002085 pixman_image_get_width(vs->vd->server),
2086 pixman_image_get_height(vs->vd->server),
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01002087 VNC_ENCODING_WMVi);
aliguorica4cca42008-09-15 16:05:16 +00002088 pixel_format_message(vs);
Corentin Charybd023f92010-07-07 20:58:02 +02002089 vnc_unlock_output(vs);
aliguorica4cca42008-09-15 16:05:16 +00002090 vnc_flush(vs);
aliguori7eac3a82008-09-15 16:03:41 +00002091 } else {
aliguori6cec5482009-01-15 22:17:38 +00002092 set_pixel_conversion(vs);
aliguori7eac3a82008-09-15 16:03:41 +00002093 }
2094}
2095
ths60fe76f2007-12-16 03:02:09 +00002096static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00002097{
2098 int i;
2099 uint16_t limit;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002100 VncDisplay *vd = vs->vd;
2101
2102 if (data[0] > 3) {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002103 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002104 }
bellard24236862006-04-30 21:28:36 +00002105
2106 switch (data[0]) {
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002107 case VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
aliguori28a76be2009-03-06 20:27:40 +00002108 if (len == 1)
2109 return 20;
bellard24236862006-04-30 21:28:36 +00002110
aliguori28a76be2009-03-06 20:27:40 +00002111 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
2112 read_u8(data, 6), read_u8(data, 7),
2113 read_u16(data, 8), read_u16(data, 10),
2114 read_u16(data, 12), read_u8(data, 14),
2115 read_u8(data, 15), read_u8(data, 16));
2116 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002117 case VNC_MSG_CLIENT_SET_ENCODINGS:
aliguori28a76be2009-03-06 20:27:40 +00002118 if (len == 1)
2119 return 4;
bellard24236862006-04-30 21:28:36 +00002120
aliguori28a76be2009-03-06 20:27:40 +00002121 if (len == 4) {
aliguori69dd5c92008-12-22 21:06:23 +00002122 limit = read_u16(data, 2);
2123 if (limit > 0)
2124 return 4 + (limit * 4);
2125 } else
2126 limit = read_u16(data, 2);
bellard24236862006-04-30 21:28:36 +00002127
aliguori28a76be2009-03-06 20:27:40 +00002128 for (i = 0; i < limit; i++) {
2129 int32_t val = read_s32(data, 4 + (i * 4));
2130 memcpy(data + 4 + (i * 4), &val, sizeof(val));
2131 }
bellard24236862006-04-30 21:28:36 +00002132
aliguori28a76be2009-03-06 20:27:40 +00002133 set_encodings(vs, (int32_t *)(data + 4), limit);
2134 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002135 case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
aliguori28a76be2009-03-06 20:27:40 +00002136 if (len == 1)
2137 return 10;
bellard24236862006-04-30 21:28:36 +00002138
aliguori28a76be2009-03-06 20:27:40 +00002139 framebuffer_update_request(vs,
2140 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
2141 read_u16(data, 6), read_u16(data, 8));
2142 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002143 case VNC_MSG_CLIENT_KEY_EVENT:
aliguori28a76be2009-03-06 20:27:40 +00002144 if (len == 1)
2145 return 8;
bellard24236862006-04-30 21:28:36 +00002146
aliguori28a76be2009-03-06 20:27:40 +00002147 key_event(vs, read_u8(data, 1), read_u32(data, 4));
2148 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002149 case VNC_MSG_CLIENT_POINTER_EVENT:
aliguori28a76be2009-03-06 20:27:40 +00002150 if (len == 1)
2151 return 6;
bellard24236862006-04-30 21:28:36 +00002152
aliguori28a76be2009-03-06 20:27:40 +00002153 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
2154 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002155 case VNC_MSG_CLIENT_CUT_TEXT:
Peter Lievenf9a70e72014-06-30 10:07:54 +02002156 if (len == 1) {
aliguori28a76be2009-03-06 20:27:40 +00002157 return 8;
Peter Lievenf9a70e72014-06-30 10:07:54 +02002158 }
aliguori28a76be2009-03-06 20:27:40 +00002159 if (len == 8) {
thsbaa76662007-09-13 12:41:42 +00002160 uint32_t dlen = read_u32(data, 4);
Peter Lievenf9a70e72014-06-30 10:07:54 +02002161 if (dlen > (1 << 20)) {
2162 error_report("vnc: client_cut_text msg payload has %u bytes"
2163 " which exceeds our limit of 1MB.", dlen);
2164 vnc_client_error(vs);
2165 break;
2166 }
2167 if (dlen > 0) {
thsbaa76662007-09-13 12:41:42 +00002168 return 8 + dlen;
Peter Lievenf9a70e72014-06-30 10:07:54 +02002169 }
thsbaa76662007-09-13 12:41:42 +00002170 }
bellard24236862006-04-30 21:28:36 +00002171
aliguori28a76be2009-03-06 20:27:40 +00002172 client_cut_text(vs, read_u32(data, 4), data + 8);
2173 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002174 case VNC_MSG_CLIENT_QEMU:
aliguori9ca313a2008-08-23 23:27:37 +00002175 if (len == 1)
2176 return 2;
2177
2178 switch (read_u8(data, 1)) {
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002179 case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00002180 if (len == 2)
2181 return 12;
2182
2183 ext_key_event(vs, read_u16(data, 2),
2184 read_u32(data, 4), read_u32(data, 8));
2185 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002186 case VNC_MSG_CLIENT_QEMU_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00002187 if (len == 2)
2188 return 4;
2189
2190 switch (read_u16 (data, 2)) {
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002191 case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
malc429a8ed2008-12-01 20:57:48 +00002192 audio_add(vs);
2193 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002194 case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
malc429a8ed2008-12-01 20:57:48 +00002195 audio_del(vs);
2196 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002197 case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
malc429a8ed2008-12-01 20:57:48 +00002198 if (len == 4)
2199 return 10;
2200 switch (read_u8(data, 4)) {
2201 case 0: vs->as.fmt = AUD_FMT_U8; break;
2202 case 1: vs->as.fmt = AUD_FMT_S8; break;
2203 case 2: vs->as.fmt = AUD_FMT_U16; break;
2204 case 3: vs->as.fmt = AUD_FMT_S16; break;
2205 case 4: vs->as.fmt = AUD_FMT_U32; break;
2206 case 5: vs->as.fmt = AUD_FMT_S32; break;
2207 default:
2208 printf("Invalid audio format %d\n", read_u8(data, 4));
2209 vnc_client_error(vs);
2210 break;
2211 }
2212 vs->as.nchannels = read_u8(data, 5);
2213 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
2214 printf("Invalid audio channel coount %d\n",
2215 read_u8(data, 5));
2216 vnc_client_error(vs);
2217 break;
2218 }
2219 vs->as.freq = read_u32(data, 6);
2220 break;
2221 default:
2222 printf ("Invalid audio message %d\n", read_u8(data, 4));
2223 vnc_client_error(vs);
2224 break;
2225 }
2226 break;
2227
aliguori9ca313a2008-08-23 23:27:37 +00002228 default:
2229 printf("Msg: %d\n", read_u16(data, 0));
2230 vnc_client_error(vs);
2231 break;
2232 }
2233 break;
bellard24236862006-04-30 21:28:36 +00002234 default:
aliguori28a76be2009-03-06 20:27:40 +00002235 printf("Msg: %d\n", data[0]);
2236 vnc_client_error(vs);
2237 break;
bellard24236862006-04-30 21:28:36 +00002238 }
ths5fafdf22007-09-16 21:08:06 +00002239
bellard24236862006-04-30 21:28:36 +00002240 vnc_read_when(vs, protocol_client_msg, 1);
2241 return 0;
2242}
2243
ths60fe76f2007-12-16 03:02:09 +00002244static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00002245{
thsc35734b2007-03-19 15:17:08 +00002246 char buf[1024];
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01002247 VncShareMode mode;
thsc35734b2007-03-19 15:17:08 +00002248 int size;
bellard24236862006-04-30 21:28:36 +00002249
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01002250 mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE;
2251 switch (vs->vd->share_policy) {
2252 case VNC_SHARE_POLICY_IGNORE:
2253 /*
2254 * Ignore the shared flag. Nothing to do here.
2255 *
2256 * Doesn't conform to the rfb spec but is traditional qemu
2257 * behavior, thus left here as option for compatibility
2258 * reasons.
2259 */
2260 break;
2261 case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE:
2262 /*
2263 * Policy: Allow clients ask for exclusive access.
2264 *
2265 * Implementation: When a client asks for exclusive access,
2266 * disconnect all others. Shared connects are allowed as long
2267 * as no exclusive connection exists.
2268 *
2269 * This is how the rfb spec suggests to handle the shared flag.
2270 */
2271 if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
2272 VncState *client;
2273 QTAILQ_FOREACH(client, &vs->vd->clients, next) {
2274 if (vs == client) {
2275 continue;
2276 }
2277 if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE &&
2278 client->share_mode != VNC_SHARE_MODE_SHARED) {
2279 continue;
2280 }
2281 vnc_disconnect_start(client);
2282 }
2283 }
2284 if (mode == VNC_SHARE_MODE_SHARED) {
2285 if (vs->vd->num_exclusive > 0) {
2286 vnc_disconnect_start(vs);
2287 return 0;
2288 }
2289 }
2290 break;
2291 case VNC_SHARE_POLICY_FORCE_SHARED:
2292 /*
2293 * Policy: Shared connects only.
2294 * Implementation: Disallow clients asking for exclusive access.
2295 *
2296 * Useful for shared desktop sessions where you don't want
2297 * someone forgetting to say -shared when running the vnc
2298 * client disconnect everybody else.
2299 */
2300 if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
2301 vnc_disconnect_start(vs);
2302 return 0;
2303 }
2304 break;
2305 }
2306 vnc_set_share_mode(vs, mode);
2307
Peter Lievenbea60dd2014-06-30 10:57:51 +02002308 vs->client_width = pixman_image_get_width(vs->vd->server);
2309 vs->client_height = pixman_image_get_height(vs->vd->server);
Gerd Hoffmann5862d192010-05-25 18:25:18 +02002310 vnc_write_u16(vs, vs->client_width);
2311 vnc_write_u16(vs, vs->client_height);
bellard24236862006-04-30 21:28:36 +00002312
aliguorica4cca42008-09-15 16:05:16 +00002313 pixel_format_message(vs);
bellard24236862006-04-30 21:28:36 +00002314
thsc35734b2007-03-19 15:17:08 +00002315 if (qemu_name)
2316 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
2317 else
2318 size = snprintf(buf, sizeof(buf), "QEMU");
2319
2320 vnc_write_u32(vs, size);
2321 vnc_write(vs, buf, size);
bellard24236862006-04-30 21:28:36 +00002322 vnc_flush(vs);
2323
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002324 vnc_client_cache_auth(vs);
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +02002325 vnc_qmp_event(vs, QAPI_EVENT_VNC_INITIALIZED);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002326
bellard24236862006-04-30 21:28:36 +00002327 vnc_read_when(vs, protocol_client_msg, 1);
2328
2329 return 0;
2330}
2331
aliguori5fb6c7a2009-03-06 20:27:23 +00002332void start_client_init(VncState *vs)
2333{
2334 vnc_read_when(vs, protocol_client_init, 1);
2335}
2336
ths70848512007-08-25 01:37:05 +00002337static void make_challenge(VncState *vs)
bellard24236862006-04-30 21:28:36 +00002338{
ths70848512007-08-25 01:37:05 +00002339 int i;
bellard24236862006-04-30 21:28:36 +00002340
ths70848512007-08-25 01:37:05 +00002341 srand(time(NULL)+getpid()+getpid()*987654+rand());
bellard24236862006-04-30 21:28:36 +00002342
ths70848512007-08-25 01:37:05 +00002343 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
2344 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
2345}
2346
ths60fe76f2007-12-16 03:02:09 +00002347static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002348{
ths60fe76f2007-12-16 03:02:09 +00002349 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
ths70848512007-08-25 01:37:05 +00002350 int i, j, pwlen;
ths60fe76f2007-12-16 03:02:09 +00002351 unsigned char key[8];
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02002352 time_t now = time(NULL);
ths70848512007-08-25 01:37:05 +00002353
Anthony Liguori1cd20f82011-01-31 14:27:36 -06002354 if (!vs->vd->password) {
aliguori28a76be2009-03-06 20:27:40 +00002355 VNC_DEBUG("No password configured on server");
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002356 goto reject;
bellard24236862006-04-30 21:28:36 +00002357 }
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02002358 if (vs->vd->expires < now) {
2359 VNC_DEBUG("Password is expired");
2360 goto reject;
2361 }
bellard24236862006-04-30 21:28:36 +00002362
ths70848512007-08-25 01:37:05 +00002363 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
2364
2365 /* Calculate the expected challenge response */
aliguori753b4052009-02-16 14:59:30 +00002366 pwlen = strlen(vs->vd->password);
ths70848512007-08-25 01:37:05 +00002367 for (i=0; i<sizeof(key); i++)
aliguori753b4052009-02-16 14:59:30 +00002368 key[i] = i<pwlen ? vs->vd->password[i] : 0;
ths70848512007-08-25 01:37:05 +00002369 deskey(key, EN0);
2370 for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
2371 des(response+j, response+j);
2372
2373 /* Compare expected vs actual challenge response */
2374 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
Dong Xu Wange5bed752011-11-22 18:06:24 +08002375 VNC_DEBUG("Client challenge response did not match\n");
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002376 goto reject;
ths70848512007-08-25 01:37:05 +00002377 } else {
aliguori28a76be2009-03-06 20:27:40 +00002378 VNC_DEBUG("Accepting VNC challenge response\n");
2379 vnc_write_u32(vs, 0); /* Accept auth */
2380 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002381
aliguori5fb6c7a2009-03-06 20:27:23 +00002382 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00002383 }
2384 return 0;
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002385
2386reject:
2387 vnc_write_u32(vs, 1); /* Reject auth */
2388 if (vs->minor >= 8) {
2389 static const char err[] = "Authentication failed";
2390 vnc_write_u32(vs, sizeof(err));
2391 vnc_write(vs, err, sizeof(err));
2392 }
2393 vnc_flush(vs);
2394 vnc_client_error(vs);
2395 return 0;
ths70848512007-08-25 01:37:05 +00002396}
2397
aliguori5fb6c7a2009-03-06 20:27:23 +00002398void start_auth_vnc(VncState *vs)
ths70848512007-08-25 01:37:05 +00002399{
2400 make_challenge(vs);
2401 /* Send client a 'random' challenge */
2402 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
bellard24236862006-04-30 21:28:36 +00002403 vnc_flush(vs);
2404
ths70848512007-08-25 01:37:05 +00002405 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
ths70848512007-08-25 01:37:05 +00002406}
2407
ths8d5d2d42007-08-25 01:37:51 +00002408
ths60fe76f2007-12-16 03:02:09 +00002409static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002410{
2411 /* We only advertise 1 auth scheme at a time, so client
2412 * must pick the one we sent. Verify this */
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002413 if (data[0] != vs->auth) { /* Reject auth */
aliguori1263b7d2009-03-06 20:27:32 +00002414 VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
ths70848512007-08-25 01:37:05 +00002415 vnc_write_u32(vs, 1);
2416 if (vs->minor >= 8) {
2417 static const char err[] = "Authentication failed";
2418 vnc_write_u32(vs, sizeof(err));
2419 vnc_write(vs, err, sizeof(err));
2420 }
2421 vnc_client_error(vs);
2422 } else { /* Accept requested auth */
2423 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002424 switch (vs->auth) {
ths70848512007-08-25 01:37:05 +00002425 case VNC_AUTH_NONE:
2426 VNC_DEBUG("Accept auth none\n");
balroga26c97a2007-10-31 01:58:56 +00002427 if (vs->minor >= 8) {
2428 vnc_write_u32(vs, 0); /* Accept auth completion */
2429 vnc_flush(vs);
2430 }
aliguori5fb6c7a2009-03-06 20:27:23 +00002431 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00002432 break;
2433
2434 case VNC_AUTH_VNC:
2435 VNC_DEBUG("Start VNC auth\n");
aliguori5fb6c7a2009-03-06 20:27:23 +00002436 start_auth_vnc(vs);
2437 break;
ths70848512007-08-25 01:37:05 +00002438
blueswir1eb38c522008-09-06 17:47:39 +00002439#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002440 case VNC_AUTH_VENCRYPT:
Dong Xu Wang3a931132011-11-29 16:52:38 +08002441 VNC_DEBUG("Accept VeNCrypt auth\n");
aliguori5fb6c7a2009-03-06 20:27:23 +00002442 start_auth_vencrypt(vs);
2443 break;
ths8d5d2d42007-08-25 01:37:51 +00002444#endif /* CONFIG_VNC_TLS */
2445
aliguori2f9606b2009-03-06 20:27:28 +00002446#ifdef CONFIG_VNC_SASL
2447 case VNC_AUTH_SASL:
2448 VNC_DEBUG("Accept SASL auth\n");
2449 start_auth_sasl(vs);
2450 break;
2451#endif /* CONFIG_VNC_SASL */
2452
ths70848512007-08-25 01:37:05 +00002453 default: /* Should not be possible, but just in case */
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002454 VNC_DEBUG("Reject auth %d server code bug\n", vs->auth);
ths70848512007-08-25 01:37:05 +00002455 vnc_write_u8(vs, 1);
2456 if (vs->minor >= 8) {
2457 static const char err[] = "Authentication failed";
2458 vnc_write_u32(vs, sizeof(err));
2459 vnc_write(vs, err, sizeof(err));
2460 }
2461 vnc_client_error(vs);
2462 }
2463 }
2464 return 0;
2465}
2466
ths60fe76f2007-12-16 03:02:09 +00002467static int protocol_version(VncState *vs, uint8_t *version, size_t len)
ths70848512007-08-25 01:37:05 +00002468{
2469 char local[13];
2470
2471 memcpy(local, version, 12);
2472 local[12] = 0;
2473
2474 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
aliguori28a76be2009-03-06 20:27:40 +00002475 VNC_DEBUG("Malformed protocol version %s\n", local);
2476 vnc_client_error(vs);
2477 return 0;
ths70848512007-08-25 01:37:05 +00002478 }
2479 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2480 if (vs->major != 3 ||
aliguori28a76be2009-03-06 20:27:40 +00002481 (vs->minor != 3 &&
2482 vs->minor != 4 &&
2483 vs->minor != 5 &&
2484 vs->minor != 7 &&
2485 vs->minor != 8)) {
2486 VNC_DEBUG("Unsupported client version\n");
2487 vnc_write_u32(vs, VNC_AUTH_INVALID);
2488 vnc_flush(vs);
2489 vnc_client_error(vs);
2490 return 0;
ths70848512007-08-25 01:37:05 +00002491 }
thsb0566f42007-09-30 13:01:15 +00002492 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
ths70848512007-08-25 01:37:05 +00002493 * as equivalent to v3.3 by servers
2494 */
thsb0566f42007-09-30 13:01:15 +00002495 if (vs->minor == 4 || vs->minor == 5)
aliguori28a76be2009-03-06 20:27:40 +00002496 vs->minor = 3;
ths70848512007-08-25 01:37:05 +00002497
2498 if (vs->minor == 3) {
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002499 if (vs->auth == VNC_AUTH_NONE) {
ths70848512007-08-25 01:37:05 +00002500 VNC_DEBUG("Tell client auth none\n");
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002501 vnc_write_u32(vs, vs->auth);
ths70848512007-08-25 01:37:05 +00002502 vnc_flush(vs);
aliguori28a76be2009-03-06 20:27:40 +00002503 start_client_init(vs);
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002504 } else if (vs->auth == VNC_AUTH_VNC) {
ths70848512007-08-25 01:37:05 +00002505 VNC_DEBUG("Tell client VNC auth\n");
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002506 vnc_write_u32(vs, vs->auth);
ths70848512007-08-25 01:37:05 +00002507 vnc_flush(vs);
2508 start_auth_vnc(vs);
2509 } else {
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002510 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
ths70848512007-08-25 01:37:05 +00002511 vnc_write_u32(vs, VNC_AUTH_INVALID);
2512 vnc_flush(vs);
2513 vnc_client_error(vs);
2514 }
2515 } else {
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002516 VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
aliguori28a76be2009-03-06 20:27:40 +00002517 vnc_write_u8(vs, 1); /* num auth */
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002518 vnc_write_u8(vs, vs->auth);
aliguori28a76be2009-03-06 20:27:40 +00002519 vnc_read_when(vs, protocol_client_auth, 1);
2520 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002521 }
bellard24236862006-04-30 21:28:36 +00002522
2523 return 0;
2524}
2525
Corentin Chary999342a2011-02-04 09:05:55 +01002526static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
2527{
2528 struct VncSurface *vs = &vd->guest;
2529
2530 return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
2531}
2532
Corentin Chary7d964c92011-02-04 09:05:56 +01002533void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
2534{
2535 int i, j;
2536
2537 w = (x + w) / VNC_STAT_RECT;
2538 h = (y + h) / VNC_STAT_RECT;
2539 x /= VNC_STAT_RECT;
2540 y /= VNC_STAT_RECT;
2541
Corentin Chary207f3282011-02-04 09:06:03 +01002542 for (j = y; j <= h; j++) {
2543 for (i = x; i <= w; i++) {
Corentin Chary7d964c92011-02-04 09:05:56 +01002544 vs->lossy_rect[j][i] = 1;
2545 }
2546 }
2547}
2548
2549static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
2550{
2551 VncState *vs;
2552 int sty = y / VNC_STAT_RECT;
2553 int stx = x / VNC_STAT_RECT;
2554 int has_dirty = 0;
2555
2556 y = y / VNC_STAT_RECT * VNC_STAT_RECT;
2557 x = x / VNC_STAT_RECT * VNC_STAT_RECT;
2558
2559 QTAILQ_FOREACH(vs, &vd->clients, next) {
Corentin Charybc2429b2011-02-04 09:06:05 +01002560 int j;
Corentin Chary7d964c92011-02-04 09:05:56 +01002561
2562 /* kernel send buffers are full -> refresh later */
2563 if (vs->output.offset) {
2564 continue;
2565 }
2566
2567 if (!vs->lossy_rect[sty][stx]) {
2568 continue;
2569 }
Corentin Chary207f3282011-02-04 09:06:03 +01002570
Corentin Chary7d964c92011-02-04 09:05:56 +01002571 vs->lossy_rect[sty][stx] = 0;
2572 for (j = 0; j < VNC_STAT_RECT; ++j) {
Peter Lievenb4c85dd2014-01-08 10:08:33 +01002573 bitmap_set(vs->dirty[y + j],
2574 x / VNC_DIRTY_PIXELS_PER_BIT,
2575 VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT);
Corentin Chary7d964c92011-02-04 09:05:56 +01002576 }
2577 has_dirty++;
2578 }
Corentin Chary207f3282011-02-04 09:06:03 +01002579
Corentin Chary7d964c92011-02-04 09:05:56 +01002580 return has_dirty;
2581}
2582
2583static int vnc_update_stats(VncDisplay *vd, struct timeval * tv)
Corentin Chary999342a2011-02-04 09:05:55 +01002584{
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002585 int width = pixman_image_get_width(vd->guest.fb);
2586 int height = pixman_image_get_height(vd->guest.fb);
Corentin Chary999342a2011-02-04 09:05:55 +01002587 int x, y;
2588 struct timeval res;
Corentin Chary7d964c92011-02-04 09:05:56 +01002589 int has_dirty = 0;
Corentin Chary999342a2011-02-04 09:05:55 +01002590
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002591 for (y = 0; y < height; y += VNC_STAT_RECT) {
2592 for (x = 0; x < width; x += VNC_STAT_RECT) {
Corentin Chary999342a2011-02-04 09:05:55 +01002593 VncRectStat *rect = vnc_stat_rect(vd, x, y);
2594
2595 rect->updated = false;
2596 }
2597 }
2598
Blue Swirlad620c22011-03-13 10:30:52 +00002599 qemu_timersub(tv, &VNC_REFRESH_STATS, &res);
Corentin Chary999342a2011-02-04 09:05:55 +01002600
2601 if (timercmp(&vd->guest.last_freq_check, &res, >)) {
Corentin Chary7d964c92011-02-04 09:05:56 +01002602 return has_dirty;
Corentin Chary999342a2011-02-04 09:05:55 +01002603 }
2604 vd->guest.last_freq_check = *tv;
2605
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002606 for (y = 0; y < height; y += VNC_STAT_RECT) {
2607 for (x = 0; x < width; x += VNC_STAT_RECT) {
Corentin Chary999342a2011-02-04 09:05:55 +01002608 VncRectStat *rect= vnc_stat_rect(vd, x, y);
2609 int count = ARRAY_SIZE(rect->times);
2610 struct timeval min, max;
2611
2612 if (!timerisset(&rect->times[count - 1])) {
2613 continue ;
2614 }
2615
2616 max = rect->times[(rect->idx + count - 1) % count];
Blue Swirlad620c22011-03-13 10:30:52 +00002617 qemu_timersub(tv, &max, &res);
Corentin Chary999342a2011-02-04 09:05:55 +01002618
2619 if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) {
2620 rect->freq = 0;
Corentin Chary7d964c92011-02-04 09:05:56 +01002621 has_dirty += vnc_refresh_lossy_rect(vd, x, y);
Corentin Chary999342a2011-02-04 09:05:55 +01002622 memset(rect->times, 0, sizeof (rect->times));
2623 continue ;
2624 }
2625
2626 min = rect->times[rect->idx];
2627 max = rect->times[(rect->idx + count - 1) % count];
Blue Swirlad620c22011-03-13 10:30:52 +00002628 qemu_timersub(&max, &min, &res);
Corentin Chary999342a2011-02-04 09:05:55 +01002629
2630 rect->freq = res.tv_sec + res.tv_usec / 1000000.;
2631 rect->freq /= count;
2632 rect->freq = 1. / rect->freq;
2633 }
2634 }
Corentin Chary7d964c92011-02-04 09:05:56 +01002635 return has_dirty;
Corentin Chary999342a2011-02-04 09:05:55 +01002636}
2637
2638double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
2639{
2640 int i, j;
2641 double total = 0;
2642 int num = 0;
2643
2644 x = (x / VNC_STAT_RECT) * VNC_STAT_RECT;
2645 y = (y / VNC_STAT_RECT) * VNC_STAT_RECT;
2646
2647 for (j = y; j <= y + h; j += VNC_STAT_RECT) {
2648 for (i = x; i <= x + w; i += VNC_STAT_RECT) {
2649 total += vnc_stat_rect(vs->vd, i, j)->freq;
2650 num++;
2651 }
2652 }
2653
2654 if (num) {
2655 return total / num;
2656 } else {
2657 return 0;
2658 }
2659}
2660
2661static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
2662{
2663 VncRectStat *rect;
2664
2665 rect = vnc_stat_rect(vd, x, y);
2666 if (rect->updated) {
2667 return ;
2668 }
2669 rect->times[rect->idx] = *tv;
2670 rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times);
2671 rect->updated = true;
2672}
2673
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002674static int vnc_refresh_server_surface(VncDisplay *vd)
2675{
Peter Lievenbea60dd2014-06-30 10:57:51 +02002676 int width = MIN(pixman_image_get_width(vd->guest.fb),
2677 pixman_image_get_width(vd->server));
2678 int height = MIN(pixman_image_get_height(vd->guest.fb),
2679 pixman_image_get_height(vd->server));
2680 int cmp_bytes, server_stride, min_stride, guest_stride, y = 0;
Peter Lieven12b316d2014-01-08 10:08:35 +01002681 uint8_t *guest_row0 = NULL, *server_row0;
Amit Shah41b4bef2010-02-05 16:34:05 +05302682 VncState *vs;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002683 int has_dirty = 0;
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002684 pixman_image_t *tmpbuf = NULL;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002685
Corentin Chary80e0c8c2011-02-04 09:06:08 +01002686 struct timeval tv = { 0, 0 };
Corentin Chary999342a2011-02-04 09:05:55 +01002687
Corentin Chary80e0c8c2011-02-04 09:06:08 +01002688 if (!vd->non_adaptive) {
2689 gettimeofday(&tv, NULL);
2690 has_dirty = vnc_update_stats(vd, &tv);
2691 }
Corentin Chary999342a2011-02-04 09:05:55 +01002692
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002693 /*
2694 * Walk through the guest dirty map.
2695 * Check and copy modified bits from guest to server surface.
2696 * Update server dirty map.
2697 */
Peter Lievenbea60dd2014-06-30 10:57:51 +02002698 server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
2699 server_stride = guest_stride = pixman_image_get_stride(vd->server);
2700 cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES,
2701 server_stride);
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002702 if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
2703 int width = pixman_image_get_width(vd->server);
2704 tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
Peter Lieven12b316d2014-01-08 10:08:35 +01002705 } else {
2706 guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
2707 guest_stride = pixman_image_get_stride(vd->guest.fb);
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002708 }
Peter Lievenbea60dd2014-06-30 10:57:51 +02002709 min_stride = MIN(server_stride, guest_stride);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002710
Peter Lieven12b316d2014-01-08 10:08:35 +01002711 for (;;) {
2712 int x;
2713 uint8_t *guest_ptr, *server_ptr;
2714 unsigned long offset = find_next_bit((unsigned long *) &vd->guest.dirty,
2715 height * VNC_DIRTY_BPL(&vd->guest),
2716 y * VNC_DIRTY_BPL(&vd->guest));
2717 if (offset == height * VNC_DIRTY_BPL(&vd->guest)) {
2718 /* no more dirty bits */
2719 break;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002720 }
Peter Lieven12b316d2014-01-08 10:08:35 +01002721 y = offset / VNC_DIRTY_BPL(&vd->guest);
2722 x = offset % VNC_DIRTY_BPL(&vd->guest);
2723
2724 server_ptr = server_row0 + y * server_stride + x * cmp_bytes;
2725
2726 if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
2727 qemu_pixman_linebuf_fill(tmpbuf, vd->guest.fb, width, 0, y);
2728 guest_ptr = (uint8_t *)pixman_image_get_data(tmpbuf);
2729 } else {
2730 guest_ptr = guest_row0 + y * guest_stride;
2731 }
2732 guest_ptr += x * cmp_bytes;
2733
2734 for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT);
2735 x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
Peter Lievenbea60dd2014-06-30 10:57:51 +02002736 int _cmp_bytes = cmp_bytes;
Peter Lieven12b316d2014-01-08 10:08:35 +01002737 if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
2738 continue;
2739 }
Peter Lievenbea60dd2014-06-30 10:57:51 +02002740 if ((x + 1) * cmp_bytes > min_stride) {
2741 _cmp_bytes = min_stride - x * cmp_bytes;
2742 }
2743 if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) {
Peter Lieven12b316d2014-01-08 10:08:35 +01002744 continue;
2745 }
Peter Lievenbea60dd2014-06-30 10:57:51 +02002746 memcpy(server_ptr, guest_ptr, _cmp_bytes);
Peter Lieven12b316d2014-01-08 10:08:35 +01002747 if (!vd->non_adaptive) {
2748 vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
2749 y, &tv);
2750 }
2751 QTAILQ_FOREACH(vs, &vd->clients, next) {
2752 set_bit(x, vs->dirty[y]);
2753 }
2754 has_dirty++;
2755 }
2756
2757 y++;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002758 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002759 qemu_pixman_image_unref(tmpbuf);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002760 return has_dirty;
2761}
2762
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002763static void vnc_refresh(DisplayChangeListener *dcl)
Stefano Stabellini703bc682009-08-03 10:54:05 +01002764{
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002765 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Amit Shah41b4bef2010-02-05 16:34:05 +05302766 VncState *vs, *vn;
2767 int has_dirty, rects = 0;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002768
Gerd Hoffmann1dbfa002013-03-12 13:44:38 +01002769 graphic_hw_update(NULL);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002770
Corentin Charybd023f92010-07-07 20:58:02 +02002771 if (vnc_trylock_display(vd)) {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002772 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
Corentin Charybd023f92010-07-07 20:58:02 +02002773 return;
2774 }
2775
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002776 has_dirty = vnc_refresh_server_surface(vd);
Corentin Charybd023f92010-07-07 20:58:02 +02002777 vnc_unlock_display(vd);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002778
Amit Shah41b4bef2010-02-05 16:34:05 +05302779 QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +01002780 rects += vnc_update_client(vs, has_dirty, false);
Stefano Stabellini6185c572010-01-25 12:54:57 +00002781 /* vs might be free()ed here */
Stefano Stabellini703bc682009-08-03 10:54:05 +01002782 }
Corentin Charybd023f92010-07-07 20:58:02 +02002783
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002784 if (QTAILQ_EMPTY(&vd->clients)) {
2785 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX);
Stefano Stabellini83755c12010-01-11 17:30:50 +00002786 return;
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002787 }
Stefano Stabellini703bc682009-08-03 10:54:05 +01002788
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002789 if (has_dirty && rects) {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002790 vd->dcl.update_interval /= 2;
2791 if (vd->dcl.update_interval < VNC_REFRESH_INTERVAL_BASE) {
2792 vd->dcl.update_interval = VNC_REFRESH_INTERVAL_BASE;
2793 }
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002794 } else {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002795 vd->dcl.update_interval += VNC_REFRESH_INTERVAL_INC;
2796 if (vd->dcl.update_interval > VNC_REFRESH_INTERVAL_MAX) {
2797 vd->dcl.update_interval = VNC_REFRESH_INTERVAL_MAX;
2798 }
Stefano Stabellini703bc682009-08-03 10:54:05 +01002799 }
2800}
2801
Michael Tokarev2c8cf542013-06-11 15:42:44 +04002802static void vnc_connect(VncDisplay *vd, int csock,
2803 bool skipauth, bool websocket)
balrog3aa3eea2008-02-03 02:54:04 +00002804{
Anthony Liguori7267c092011-08-20 22:09:37 -05002805 VncState *vs = g_malloc0(sizeof(VncState));
Corentin Chary7d964c92011-02-04 09:05:56 +01002806 int i;
2807
aliguori753b4052009-02-16 14:59:30 +00002808 vs->csock = csock;
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002809
2810 if (skipauth) {
2811 vs->auth = VNC_AUTH_NONE;
2812#ifdef CONFIG_VNC_TLS
2813 vs->subauth = VNC_AUTH_INVALID;
2814#endif
2815 } else {
2816 vs->auth = vd->auth;
2817#ifdef CONFIG_VNC_TLS
2818 vs->subauth = vd->subauth;
2819#endif
2820 }
2821
Anthony Liguori7267c092011-08-20 22:09:37 -05002822 vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
Corentin Chary7d964c92011-02-04 09:05:56 +01002823 for (i = 0; i < VNC_STAT_ROWS; ++i) {
Anthony Liguori7267c092011-08-20 22:09:37 -05002824 vs->lossy_rect[i] = g_malloc0(VNC_STAT_COLS * sizeof (uint8_t));
Corentin Chary7d964c92011-02-04 09:05:56 +01002825 }
aliguori753b4052009-02-16 14:59:30 +00002826
2827 VNC_DEBUG("New client on socket %d\n", csock);
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002828 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
Stefan Hajnoczif9e8cac2013-03-27 10:10:43 +01002829 qemu_set_nonblock(vs->csock);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002830#ifdef CONFIG_VNC_WS
2831 if (websocket) {
2832 vs->websocket = 1;
Tim Hardeck0057a0d2013-04-23 16:33:01 +02002833#ifdef CONFIG_VNC_TLS
2834 if (vd->tls.x509cert) {
2835 qemu_set_fd_handler2(vs->csock, NULL, vncws_tls_handshake_peek,
2836 NULL, vs);
2837 } else
2838#endif /* CONFIG_VNC_TLS */
2839 {
2840 qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read,
2841 NULL, vs);
2842 }
Tim Hardeck7536ee42013-01-21 11:04:44 +01002843 } else
2844#endif /* CONFIG_VNC_WS */
2845 {
2846 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
2847 }
aliguori753b4052009-02-16 14:59:30 +00002848
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002849 vnc_client_cache_addr(vs);
Wenchao Xiafb6ba0d2014-06-18 08:43:49 +02002850 vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED);
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01002851 vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002852
aliguori753b4052009-02-16 14:59:30 +00002853 vs->vd = vd;
Tim Hardeck7536ee42013-01-21 11:04:44 +01002854
2855#ifdef CONFIG_VNC_WS
2856 if (!vs->websocket)
2857#endif
2858 {
2859 vnc_init_state(vs);
2860 }
2861}
2862
2863void vnc_init_state(VncState *vs)
2864{
Tim Hardeck6fd8e792013-01-21 11:04:45 +01002865 vs->initialized = true;
Tim Hardeck7536ee42013-01-21 11:04:44 +01002866 VncDisplay *vd = vs->vd;
2867
aliguori753b4052009-02-16 14:59:30 +00002868 vs->last_x = -1;
2869 vs->last_y = -1;
2870
2871 vs->as.freq = 44100;
2872 vs->as.nchannels = 2;
2873 vs->as.fmt = AUD_FMT_S16;
2874 vs->as.endianness = 0;
2875
Corentin Charybd023f92010-07-07 20:58:02 +02002876 qemu_mutex_init(&vs->output_mutex);
Corentin Chary175b2a62012-03-14 07:58:47 +01002877 vs->bh = qemu_bh_new(vnc_jobs_bh, vs);
Corentin Charybd023f92010-07-07 20:58:02 +02002878
Amit Shah41b4bef2010-02-05 16:34:05 +05302879 QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002880
Gerd Hoffmann1dbfa002013-03-12 13:44:38 +01002881 graphic_hw_update(NULL);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002882
balrog3aa3eea2008-02-03 02:54:04 +00002883 vnc_write(vs, "RFB 003.008\n", 12);
2884 vnc_flush(vs);
2885 vnc_read_when(vs, protocol_version, 12);
malc53762dd2008-12-01 20:57:52 +00002886 reset_keys(vs);
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01002887 if (vs->vd->lock_key_sync)
2888 vs->led = qemu_add_led_event_handler(kbd_leds, vs);
aliguori753b4052009-02-16 14:59:30 +00002889
Anthony Liguori37c34d92010-03-10 09:38:29 -06002890 vs->mouse_mode_notifier.notify = check_pointer_type_change;
2891 qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
2892
Gerd Hoffmann198a0032009-06-16 14:19:48 +02002893 /* vs might be free()ed here */
balrog3aa3eea2008-02-03 02:54:04 +00002894}
2895
Tim Hardeck7536ee42013-01-21 11:04:44 +01002896static void vnc_listen_read(void *opaque, bool websocket)
bellard24236862006-04-30 21:28:36 +00002897{
aliguori753b4052009-02-16 14:59:30 +00002898 VncDisplay *vs = opaque;
bellard24236862006-04-30 21:28:36 +00002899 struct sockaddr_in addr;
2900 socklen_t addrlen = sizeof(addr);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002901 int csock;
bellard24236862006-04-30 21:28:36 +00002902
balrog9f60ad52008-01-14 21:45:55 +00002903 /* Catch-up */
Gerd Hoffmann1dbfa002013-03-12 13:44:38 +01002904 graphic_hw_update(NULL);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002905#ifdef CONFIG_VNC_WS
2906 if (websocket) {
2907 csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen);
2908 } else
2909#endif /* CONFIG_VNC_WS */
2910 {
2911 csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
2912 }
balrog9f60ad52008-01-14 21:45:55 +00002913
aliguori753b4052009-02-16 14:59:30 +00002914 if (csock != -1) {
Michael Tokarev2c8cf542013-06-11 15:42:44 +04002915 vnc_connect(vs, csock, false, websocket);
bellard24236862006-04-30 21:28:36 +00002916 }
2917}
2918
Tim Hardeck7536ee42013-01-21 11:04:44 +01002919static void vnc_listen_regular_read(void *opaque)
2920{
Michael Tokarev2c8cf542013-06-11 15:42:44 +04002921 vnc_listen_read(opaque, false);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002922}
2923
2924#ifdef CONFIG_VNC_WS
2925static void vnc_listen_websocket_read(void *opaque)
2926{
Michael Tokarev2c8cf542013-06-11 15:42:44 +04002927 vnc_listen_read(opaque, true);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002928}
2929#endif /* CONFIG_VNC_WS */
2930
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01002931static const DisplayChangeListenerOps dcl_ops = {
2932 .dpy_name = "vnc",
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002933 .dpy_refresh = vnc_refresh,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01002934 .dpy_gfx_copy = vnc_dpy_copy,
2935 .dpy_gfx_update = vnc_dpy_update,
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +01002936 .dpy_gfx_switch = vnc_dpy_switch,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01002937 .dpy_mouse_set = vnc_mouse_set,
2938 .dpy_cursor_define = vnc_dpy_cursor_define,
2939};
2940
ths71cab5c2007-08-25 01:35:38 +00002941void vnc_display_init(DisplayState *ds)
bellard24236862006-04-30 21:28:36 +00002942{
Anthony Liguori7267c092011-08-20 22:09:37 -05002943 VncDisplay *vs = g_malloc0(sizeof(*vs));
bellard24236862006-04-30 21:28:36 +00002944
aliguori753b4052009-02-16 14:59:30 +00002945 vnc_display = vs;
bellard24236862006-04-30 21:28:36 +00002946
2947 vs->lsock = -1;
Tim Hardeck7536ee42013-01-21 11:04:44 +01002948#ifdef CONFIG_VNC_WS
2949 vs->lwebsock = -1;
2950#endif
bellard24236862006-04-30 21:28:36 +00002951
Amit Shah41b4bef2010-02-05 16:34:05 +05302952 QTAILQ_INIT(&vs->clients);
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02002953 vs->expires = TIME_MAX;
bellard24236862006-04-30 21:28:36 +00002954
Gerd Hoffmann40066172014-05-21 13:18:20 +02002955 if (keyboard_layout) {
2956 trace_vnc_key_map_init(keyboard_layout);
aliguori04837552009-03-06 20:27:10 +00002957 vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
Gerd Hoffmann40066172014-05-21 13:18:20 +02002958 } else {
aliguori04837552009-03-06 20:27:10 +00002959 vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
Gerd Hoffmann40066172014-05-21 13:18:20 +02002960 }
bellard24236862006-04-30 21:28:36 +00002961
bellard24236862006-04-30 21:28:36 +00002962 if (!vs->kbd_layout)
aliguori28a76be2009-03-06 20:27:40 +00002963 exit(1);
bellard24236862006-04-30 21:28:36 +00002964
Corentin Charybd023f92010-07-07 20:58:02 +02002965 qemu_mutex_init(&vs->mutex);
2966 vnc_start_worker_thread();
Corentin Charybd023f92010-07-07 20:58:02 +02002967
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01002968 vs->dcl.ops = &dcl_ops;
Gerd Hoffmann52090892013-04-23 15:44:31 +02002969 register_displaychangelistener(&vs->dcl);
ths71cab5c2007-08-25 01:35:38 +00002970}
ths73fc9742006-12-22 02:09:07 +00002971
ths6f430242007-08-25 01:39:57 +00002972
Blue Swirl71a8cde2012-10-28 11:04:48 +00002973static void vnc_display_close(DisplayState *ds)
ths71cab5c2007-08-25 01:35:38 +00002974{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01002975 VncDisplay *vs = vnc_display;
ths71cab5c2007-08-25 01:35:38 +00002976
aliguori452b4d82009-02-11 21:00:38 +00002977 if (!vs)
2978 return;
Markus Armbruster64641d82014-06-06 18:47:43 +02002979 g_free(vs->display);
2980 vs->display = NULL;
ths71cab5c2007-08-25 01:35:38 +00002981 if (vs->lsock != -1) {
aliguori28a76be2009-03-06 20:27:40 +00002982 qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
2983 close(vs->lsock);
2984 vs->lsock = -1;
ths71cab5c2007-08-25 01:35:38 +00002985 }
Tim Hardeck7536ee42013-01-21 11:04:44 +01002986#ifdef CONFIG_VNC_WS
2987 g_free(vs->ws_display);
2988 vs->ws_display = NULL;
2989 if (vs->lwebsock != -1) {
2990 qemu_set_fd_handler2(vs->lwebsock, NULL, NULL, NULL, NULL);
2991 close(vs->lwebsock);
2992 vs->lwebsock = -1;
2993 }
2994#endif /* CONFIG_VNC_WS */
ths70848512007-08-25 01:37:05 +00002995 vs->auth = VNC_AUTH_INVALID;
blueswir1eb38c522008-09-06 17:47:39 +00002996#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002997 vs->subauth = VNC_AUTH_INVALID;
aliguori5fb6c7a2009-03-06 20:27:23 +00002998 vs->tls.x509verify = 0;
ths8d5d2d42007-08-25 01:37:51 +00002999#endif
ths71cab5c2007-08-25 01:35:38 +00003000}
3001
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003002int vnc_display_password(DisplayState *ds, const char *password)
3003{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003004 VncDisplay *vs = vnc_display;
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003005
3006 if (!vs) {
Luiz Capitulinoa6aa9d32011-12-07 10:19:10 -02003007 return -EINVAL;
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003008 }
Gerd Hoffmanncf864562013-12-11 13:15:37 +01003009 if (vs->auth == VNC_AUTH_NONE) {
3010 error_printf_unless_qmp("If you want use passwords please enable "
3011 "password auth using '-vnc ${dpy},password'.");
3012 return -EINVAL;
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003013 }
3014
Markus Armbruster64641d82014-06-06 18:47:43 +02003015 g_free(vs->password);
Markus Armbrusterc14e9842014-06-06 18:47:44 +02003016 vs->password = g_strdup(password);
Luiz Capitulinoa6aa9d32011-12-07 10:19:10 -02003017
3018 return 0;
ths70848512007-08-25 01:37:05 +00003019}
3020
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003021int vnc_display_pw_expire(DisplayState *ds, time_t expires)
3022{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003023 VncDisplay *vs = vnc_display;
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003024
Gerd Hoffmann1643f2b2012-05-24 10:55:01 +02003025 if (!vs) {
3026 return -EINVAL;
3027 }
3028
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003029 vs->expires = expires;
3030 return 0;
3031}
3032
Anthony Liguorif92f8af2009-05-20 13:01:02 -05003033char *vnc_display_local_addr(DisplayState *ds)
3034{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003035 VncDisplay *vs = vnc_display;
Anthony Liguorif92f8af2009-05-20 13:01:02 -05003036
3037 return vnc_socket_local_addr("%s:%s", vs->lsock);
3038}
3039
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003040void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
ths71cab5c2007-08-25 01:35:38 +00003041{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003042 VncDisplay *vs = vnc_display;
ths70848512007-08-25 01:37:05 +00003043 const char *options;
3044 int password = 0;
balrog3aa3eea2008-02-03 02:54:04 +00003045 int reverse = 0;
blueswir1eb38c522008-09-06 17:47:39 +00003046#ifdef CONFIG_VNC_TLS
ths3a702692007-08-25 01:38:36 +00003047 int tls = 0, x509 = 0;
ths8d5d2d42007-08-25 01:37:51 +00003048#endif
aliguori2f9606b2009-03-06 20:27:28 +00003049#ifdef CONFIG_VNC_SASL
3050 int sasl = 0;
3051 int saslErr;
3052#endif
Blue Swirl2ded6ad2010-10-13 18:38:08 +00003053#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
aliguori76655d62009-03-06 20:27:37 +00003054 int acl = 0;
Blue Swirl2ded6ad2010-10-13 18:38:08 +00003055#endif
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01003056 int lock_key_sync = 1;
ths71cab5c2007-08-25 01:35:38 +00003057
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003058 if (!vnc_display) {
3059 error_setg(errp, "VNC display not active");
3060 return;
3061 }
ths71cab5c2007-08-25 01:35:38 +00003062 vnc_display_close(ds);
ths70848512007-08-25 01:37:05 +00003063 if (strcmp(display, "none") == 0)
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003064 return;
ths71cab5c2007-08-25 01:35:38 +00003065
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003066 vs->display = g_strdup(display);
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01003067 vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
ths70848512007-08-25 01:37:05 +00003068
3069 options = display;
3070 while ((options = strchr(options, ','))) {
aliguori28a76be2009-03-06 20:27:40 +00003071 options++;
3072 if (strncmp(options, "password", 8) == 0) {
Paul Moore0f669982012-08-03 14:39:21 -04003073 if (fips_get_state()) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003074 error_setg(errp,
3075 "VNC password auth disabled due to FIPS mode, "
3076 "consider using the VeNCrypt or SASL authentication "
3077 "methods as an alternative");
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003078 goto fail;
Paul Moore0f669982012-08-03 14:39:21 -04003079 }
aliguori28a76be2009-03-06 20:27:40 +00003080 password = 1; /* Require password auth */
3081 } else if (strncmp(options, "reverse", 7) == 0) {
3082 reverse = 1;
Stefan Hajnoczicee8e6a2012-01-06 16:57:45 +00003083 } else if (strncmp(options, "no-lock-key-sync", 16) == 0) {
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01003084 lock_key_sync = 0;
aliguori2f9606b2009-03-06 20:27:28 +00003085#ifdef CONFIG_VNC_SASL
aliguori28a76be2009-03-06 20:27:40 +00003086 } else if (strncmp(options, "sasl", 4) == 0) {
3087 sasl = 1; /* Require SASL auth */
aliguori2f9606b2009-03-06 20:27:28 +00003088#endif
Tim Hardeck7536ee42013-01-21 11:04:44 +01003089#ifdef CONFIG_VNC_WS
3090 } else if (strncmp(options, "websocket", 9) == 0) {
3091 char *start, *end;
3092 vs->websocket = 1;
3093
3094 /* Check for 'websocket=<port>' */
3095 start = strchr(options, '=');
3096 end = strchr(options, ',');
3097 if (start && (!end || (start < end))) {
3098 int len = end ? end-(start+1) : strlen(start+1);
3099 if (len < 6) {
3100 /* extract the host specification from display */
3101 char *host = NULL, *port = NULL, *host_end = NULL;
3102 port = g_strndup(start + 1, len);
3103
3104 /* ipv6 hosts have colons */
3105 end = strchr(display, ',');
3106 host_end = g_strrstr_len(display, end - display, ":");
3107
3108 if (host_end) {
3109 host = g_strndup(display, host_end - display + 1);
3110 } else {
3111 host = g_strndup(":", 1);
3112 }
3113 vs->ws_display = g_strconcat(host, port, NULL);
3114 g_free(host);
3115 g_free(port);
3116 }
3117 }
3118#endif /* CONFIG_VNC_WS */
blueswir1eb38c522008-09-06 17:47:39 +00003119#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003120 } else if (strncmp(options, "tls", 3) == 0) {
3121 tls = 1; /* Require TLS */
3122 } else if (strncmp(options, "x509", 4) == 0) {
3123 char *start, *end;
3124 x509 = 1; /* Require x509 certificates */
3125 if (strncmp(options, "x509verify", 10) == 0)
3126 vs->tls.x509verify = 1; /* ...and verify client certs */
ths6f430242007-08-25 01:39:57 +00003127
aliguori28a76be2009-03-06 20:27:40 +00003128 /* Now check for 'x509=/some/path' postfix
3129 * and use that to setup x509 certificate/key paths */
3130 start = strchr(options, '=');
3131 end = strchr(options, ',');
3132 if (start && (!end || (start < end))) {
3133 int len = end ? end-(start+1) : strlen(start+1);
Anthony Liguori7267c092011-08-20 22:09:37 -05003134 char *path = g_strndup(start + 1, len);
blueswir1be15b142008-10-25 11:21:28 +00003135
aliguori28a76be2009-03-06 20:27:40 +00003136 VNC_DEBUG("Trying certificate path '%s'\n", path);
3137 if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003138 error_setg(errp, "Failed to find x509 certificates/keys in %s", path);
Anthony Liguori7267c092011-08-20 22:09:37 -05003139 g_free(path);
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003140 goto fail;
aliguori28a76be2009-03-06 20:27:40 +00003141 }
Anthony Liguori7267c092011-08-20 22:09:37 -05003142 g_free(path);
aliguori28a76be2009-03-06 20:27:40 +00003143 } else {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003144 error_setg(errp, "No certificate path provided");
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003145 goto fail;
aliguori28a76be2009-03-06 20:27:40 +00003146 }
ths8d5d2d42007-08-25 01:37:51 +00003147#endif
Blue Swirl2ded6ad2010-10-13 18:38:08 +00003148#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
aliguori28a76be2009-03-06 20:27:40 +00003149 } else if (strncmp(options, "acl", 3) == 0) {
3150 acl = 1;
Blue Swirl2ded6ad2010-10-13 18:38:08 +00003151#endif
Corentin Chary6f9c78c2010-07-07 20:57:51 +02003152 } else if (strncmp(options, "lossy", 5) == 0) {
Peter Lievene22492d2014-01-08 10:08:38 +01003153#ifdef CONFIG_VNC_JPEG
Corentin Chary6f9c78c2010-07-07 20:57:51 +02003154 vs->lossy = true;
Peter Lievene22492d2014-01-08 10:08:38 +01003155#endif
Catalin Patulea7eff5742012-11-09 19:01:26 -05003156 } else if (strncmp(options, "non-adaptive", 12) == 0) {
Corentin Chary80e0c8c2011-02-04 09:06:08 +01003157 vs->non_adaptive = true;
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01003158 } else if (strncmp(options, "share=", 6) == 0) {
3159 if (strncmp(options+6, "ignore", 6) == 0) {
3160 vs->share_policy = VNC_SHARE_POLICY_IGNORE;
3161 } else if (strncmp(options+6, "allow-exclusive", 15) == 0) {
3162 vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
3163 } else if (strncmp(options+6, "force-shared", 12) == 0) {
3164 vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
3165 } else {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003166 error_setg(errp, "unknown vnc share= option");
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003167 goto fail;
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01003168 }
aliguori28a76be2009-03-06 20:27:40 +00003169 }
ths70848512007-08-25 01:37:05 +00003170 }
3171
Peter Lievene22492d2014-01-08 10:08:38 +01003172 /* adaptive updates are only used with tight encoding and
3173 * if lossy updates are enabled so we can disable all the
3174 * calculations otherwise */
3175 if (!vs->lossy) {
3176 vs->non_adaptive = true;
3177 }
3178
aliguori76655d62009-03-06 20:27:37 +00003179#ifdef CONFIG_VNC_TLS
3180 if (acl && x509 && vs->tls.x509verify) {
aliguori28a76be2009-03-06 20:27:40 +00003181 if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
3182 fprintf(stderr, "Failed to create x509 dname ACL\n");
3183 exit(1);
3184 }
aliguori76655d62009-03-06 20:27:37 +00003185 }
3186#endif
3187#ifdef CONFIG_VNC_SASL
3188 if (acl && sasl) {
aliguori28a76be2009-03-06 20:27:40 +00003189 if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
3190 fprintf(stderr, "Failed to create username ACL\n");
3191 exit(1);
3192 }
aliguori76655d62009-03-06 20:27:37 +00003193 }
3194#endif
3195
aliguori2f9606b2009-03-06 20:27:28 +00003196 /*
3197 * Combinations we support here:
3198 *
3199 * - no-auth (clear text, no auth)
3200 * - password (clear text, weak auth)
3201 * - sasl (encrypt, good auth *IF* using Kerberos via GSSAPI)
3202 * - tls (encrypt, weak anonymous creds, no auth)
3203 * - tls + password (encrypt, weak anonymous creds, weak auth)
3204 * - tls + sasl (encrypt, weak anonymous creds, good auth)
3205 * - tls + x509 (encrypt, good x509 creds, no auth)
3206 * - tls + x509 + password (encrypt, good x509 creds, weak auth)
3207 * - tls + x509 + sasl (encrypt, good x509 creds, good auth)
3208 *
3209 * NB1. TLS is a stackable auth scheme.
3210 * NB2. the x509 schemes have option to validate a client cert dname
3211 */
ths70848512007-08-25 01:37:05 +00003212 if (password) {
blueswir1eb38c522008-09-06 17:47:39 +00003213#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003214 if (tls) {
3215 vs->auth = VNC_AUTH_VENCRYPT;
3216 if (x509) {
3217 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
3218 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
3219 } else {
3220 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
3221 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
3222 }
3223 } else {
aliguori2f9606b2009-03-06 20:27:28 +00003224#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00003225 VNC_DEBUG("Initializing VNC server with password auth\n");
3226 vs->auth = VNC_AUTH_VNC;
blueswir1eb38c522008-09-06 17:47:39 +00003227#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003228 vs->subauth = VNC_AUTH_INVALID;
3229 }
aliguori2f9606b2009-03-06 20:27:28 +00003230#endif /* CONFIG_VNC_TLS */
3231#ifdef CONFIG_VNC_SASL
3232 } else if (sasl) {
3233#ifdef CONFIG_VNC_TLS
3234 if (tls) {
3235 vs->auth = VNC_AUTH_VENCRYPT;
3236 if (x509) {
aliguori28a76be2009-03-06 20:27:40 +00003237 VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00003238 vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
3239 } else {
aliguori28a76be2009-03-06 20:27:40 +00003240 VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00003241 vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
3242 }
3243 } else {
3244#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00003245 VNC_DEBUG("Initializing VNC server with SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00003246 vs->auth = VNC_AUTH_SASL;
3247#ifdef CONFIG_VNC_TLS
3248 vs->subauth = VNC_AUTH_INVALID;
3249 }
3250#endif /* CONFIG_VNC_TLS */
3251#endif /* CONFIG_VNC_SASL */
ths70848512007-08-25 01:37:05 +00003252 } else {
blueswir1eb38c522008-09-06 17:47:39 +00003253#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003254 if (tls) {
3255 vs->auth = VNC_AUTH_VENCRYPT;
3256 if (x509) {
3257 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
3258 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
3259 } else {
3260 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
3261 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
3262 }
3263 } else {
ths8d5d2d42007-08-25 01:37:51 +00003264#endif
aliguori28a76be2009-03-06 20:27:40 +00003265 VNC_DEBUG("Initializing VNC server with no auth\n");
3266 vs->auth = VNC_AUTH_NONE;
blueswir1eb38c522008-09-06 17:47:39 +00003267#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003268 vs->subauth = VNC_AUTH_INVALID;
3269 }
ths8d5d2d42007-08-25 01:37:51 +00003270#endif
ths70848512007-08-25 01:37:05 +00003271 }
bellard24236862006-04-30 21:28:36 +00003272
aliguori2f9606b2009-03-06 20:27:28 +00003273#ifdef CONFIG_VNC_SASL
3274 if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003275 error_setg(errp, "Failed to initialize SASL auth: %s",
3276 sasl_errstring(saslErr, NULL, NULL));
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003277 goto fail;
aliguori2f9606b2009-03-06 20:27:28 +00003278 }
3279#endif
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01003280 vs->lock_key_sync = lock_key_sync;
aliguori2f9606b2009-03-06 20:27:28 +00003281
balrog3aa3eea2008-02-03 02:54:04 +00003282 if (reverse) {
aliguori9712eca2008-11-11 20:51:59 +00003283 /* connect to viewer */
Paolo Bonzini007fcd3e2012-10-18 09:01:01 +02003284 int csock;
3285 vs->lsock = -1;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003286#ifdef CONFIG_VNC_WS
3287 vs->lwebsock = -1;
3288#endif
Paolo Bonzini007fcd3e2012-10-18 09:01:01 +02003289 if (strncmp(display, "unix:", 5) == 0) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003290 csock = unix_connect(display+5, errp);
balrog3aa3eea2008-02-03 02:54:04 +00003291 } else {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003292 csock = inet_connect(display, errp);
balrog3aa3eea2008-02-03 02:54:04 +00003293 }
Paolo Bonzini007fcd3e2012-10-18 09:01:01 +02003294 if (csock < 0) {
3295 goto fail;
3296 }
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003297 vnc_connect(vs, csock, false, false);
aliguori9712eca2008-11-11 20:51:59 +00003298 } else {
3299 /* listen for connects */
3300 char *dpy;
Anthony Liguori7267c092011-08-20 22:09:37 -05003301 dpy = g_malloc(256);
aliguori9712eca2008-11-11 20:51:59 +00003302 if (strncmp(display, "unix:", 5) == 0) {
blueswir1bc575e92009-01-14 18:34:22 +00003303 pstrcpy(dpy, 256, "unix:");
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003304 vs->lsock = unix_listen(display+5, dpy+5, 256-5, errp);
aliguori9712eca2008-11-11 20:51:59 +00003305 } else {
Amos Kong029409e2012-05-11 00:28:26 +08003306 vs->lsock = inet_listen(display, dpy, 256,
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003307 SOCK_STREAM, 5900, errp);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003308 if (vs->lsock < 0) {
3309 g_free(dpy);
3310 goto fail;
3311 }
3312#ifdef CONFIG_VNC_WS
3313 if (vs->websocket) {
3314 if (vs->ws_display) {
3315 vs->lwebsock = inet_listen(vs->ws_display, NULL, 256,
3316 SOCK_STREAM, 0, errp);
3317 } else {
3318 vs->lwebsock = inet_listen(vs->display, NULL, 256,
3319 SOCK_STREAM, 5700, errp);
3320 }
3321
3322 if (vs->lwebsock < 0) {
3323 if (vs->lsock) {
3324 close(vs->lsock);
3325 vs->lsock = -1;
3326 }
3327 g_free(dpy);
3328 goto fail;
3329 }
3330 }
3331#endif /* CONFIG_VNC_WS */
aliguori9712eca2008-11-11 20:51:59 +00003332 }
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003333 g_free(vs->display);
3334 vs->display = dpy;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003335 qemu_set_fd_handler2(vs->lsock, NULL,
3336 vnc_listen_regular_read, NULL, vs);
3337#ifdef CONFIG_VNC_WS
3338 if (vs->websocket) {
3339 qemu_set_fd_handler2(vs->lwebsock, NULL,
3340 vnc_listen_websocket_read, NULL, vs);
3341 }
3342#endif /* CONFIG_VNC_WS */
bellard24236862006-04-30 21:28:36 +00003343 }
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003344 return;
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003345
3346fail:
3347 g_free(vs->display);
3348 vs->display = NULL;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003349#ifdef CONFIG_VNC_WS
3350 g_free(vs->ws_display);
3351 vs->ws_display = NULL;
3352#endif /* CONFIG_VNC_WS */
bellard24236862006-04-30 21:28:36 +00003353}
Daniel P. Berrange13661082011-06-23 13:31:42 +01003354
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003355void vnc_display_add_client(DisplayState *ds, int csock, bool skipauth)
Daniel P. Berrange13661082011-06-23 13:31:42 +01003356{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003357 VncDisplay *vs = vnc_display;
Daniel P. Berrange13661082011-06-23 13:31:42 +01003358
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003359 vnc_connect(vs, csock, skipauth, false);
Daniel P. Berrange13661082011-06-23 13:31:42 +01003360}