blob: 1684206184a22c5d9e1f0a69542e78b78a7aad31 [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"
bellard24236862006-04-30 21:28:36 +000038
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +010039#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
Stefano Stabellini2430ffe2009-08-03 10:56:01 +010040#define VNC_REFRESH_INTERVAL_INC 50
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +010041#define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE
Corentin Chary999342a2011-02-04 09:05:55 +010042static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
43static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
bellard24236862006-04-30 21:28:36 +000044
45#include "vnc_keysym.h"
ths70848512007-08-25 01:37:05 +000046#include "d3des.h"
47
aliguori753b4052009-02-16 14:59:30 +000048static VncDisplay *vnc_display; /* needed for info vnc */
bellarda9ce8592007-02-05 20:20:30 +000049
Gerd Hoffmannd467b672010-05-21 11:54:34 +020050static int vnc_cursor_define(VncState *vs);
Gerd Hoffmann7bc93182012-02-08 13:18:37 +010051static void vnc_release_modifiers(VncState *vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +020052
Gerd Hoffmann8cf36482011-11-24 18:10:49 +010053static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
54{
55#ifdef _VNC_DEBUG
56 static const char *mn[] = {
57 [0] = "undefined",
58 [VNC_SHARE_MODE_CONNECTING] = "connecting",
59 [VNC_SHARE_MODE_SHARED] = "shared",
60 [VNC_SHARE_MODE_EXCLUSIVE] = "exclusive",
61 [VNC_SHARE_MODE_DISCONNECTED] = "disconnected",
62 };
63 fprintf(stderr, "%s/%d: %s -> %s\n", __func__,
64 vs->csock, mn[vs->share_mode], mn[mode]);
65#endif
66
67 if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
68 vs->vd->num_exclusive--;
69 }
70 vs->share_mode = mode;
71 if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
72 vs->vd->num_exclusive++;
73 }
74}
75
aliguori1ff7df12009-03-06 20:27:05 +000076static char *addr_to_string(const char *format,
77 struct sockaddr_storage *sa,
78 socklen_t salen) {
79 char *addr;
80 char host[NI_MAXHOST];
81 char serv[NI_MAXSERV];
82 int err;
aliguori457772e2009-03-13 15:03:27 +000083 size_t addrlen;
aliguori1ff7df12009-03-06 20:27:05 +000084
85 if ((err = getnameinfo((struct sockaddr *)sa, salen,
86 host, sizeof(host),
87 serv, sizeof(serv),
88 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
89 VNC_DEBUG("Cannot resolve address %d: %s\n",
90 err, gai_strerror(err));
91 return NULL;
92 }
93
aliguori457772e2009-03-13 15:03:27 +000094 /* Enough for the existing format + the 2 vars we're
Stefan Weilf425c272009-06-06 17:00:31 +020095 * substituting in. */
aliguori457772e2009-03-13 15:03:27 +000096 addrlen = strlen(format) + strlen(host) + strlen(serv);
Anthony Liguori7267c092011-08-20 22:09:37 -050097 addr = g_malloc(addrlen + 1);
aliguori457772e2009-03-13 15:03:27 +000098 snprintf(addr, addrlen, format, host, serv);
99 addr[addrlen] = '\0';
aliguori1ff7df12009-03-06 20:27:05 +0000100
101 return addr;
102}
103
aliguori2f9606b2009-03-06 20:27:28 +0000104
105char *vnc_socket_local_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +0000106 struct sockaddr_storage sa;
107 socklen_t salen;
108
109 salen = sizeof(sa);
110 if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
111 return NULL;
112
113 return addr_to_string(format, &sa, salen);
114}
115
aliguori2f9606b2009-03-06 20:27:28 +0000116char *vnc_socket_remote_addr(const char *format, int fd) {
aliguori1ff7df12009-03-06 20:27:05 +0000117 struct sockaddr_storage sa;
118 socklen_t salen;
119
120 salen = sizeof(sa);
121 if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
122 return NULL;
123
124 return addr_to_string(format, &sa, salen);
125}
126
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200127static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa,
128 socklen_t salen)
129{
130 char host[NI_MAXHOST];
131 char serv[NI_MAXSERV];
132 int err;
133
134 if ((err = getnameinfo((struct sockaddr *)sa, salen,
135 host, sizeof(host),
136 serv, sizeof(serv),
137 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
138 VNC_DEBUG("Cannot resolve address %d: %s\n",
139 err, gai_strerror(err));
140 return -1;
141 }
142
143 qdict_put(qdict, "host", qstring_from_str(host));
144 qdict_put(qdict, "service", qstring_from_str(serv));
Luiz Capitulinodc0d4ef2010-01-20 11:42:40 -0200145 qdict_put(qdict, "family",qstring_from_str(inet_strfamily(sa->ss_family)));
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200146
147 return 0;
148}
149
Luiz Capitulinoa7789382010-01-14 14:50:53 -0200150static int vnc_server_addr_put(QDict *qdict, int fd)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200151{
152 struct sockaddr_storage sa;
153 socklen_t salen;
154
155 salen = sizeof(sa);
156 if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
157 return -1;
158 }
159
160 return put_addr_qdict(qdict, &sa, salen);
161}
162
163static int vnc_qdict_remote_addr(QDict *qdict, int fd)
164{
165 struct sockaddr_storage sa;
166 socklen_t salen;
167
168 salen = sizeof(sa);
169 if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
170 return -1;
171 }
172
173 return put_addr_qdict(qdict, &sa, salen);
174}
175
aliguori1ff7df12009-03-06 20:27:05 +0000176static const char *vnc_auth_name(VncDisplay *vd) {
177 switch (vd->auth) {
178 case VNC_AUTH_INVALID:
179 return "invalid";
180 case VNC_AUTH_NONE:
181 return "none";
182 case VNC_AUTH_VNC:
183 return "vnc";
184 case VNC_AUTH_RA2:
185 return "ra2";
186 case VNC_AUTH_RA2NE:
187 return "ra2ne";
188 case VNC_AUTH_TIGHT:
189 return "tight";
190 case VNC_AUTH_ULTRA:
191 return "ultra";
192 case VNC_AUTH_TLS:
193 return "tls";
194 case VNC_AUTH_VENCRYPT:
195#ifdef CONFIG_VNC_TLS
196 switch (vd->subauth) {
197 case VNC_AUTH_VENCRYPT_PLAIN:
198 return "vencrypt+plain";
199 case VNC_AUTH_VENCRYPT_TLSNONE:
200 return "vencrypt+tls+none";
201 case VNC_AUTH_VENCRYPT_TLSVNC:
202 return "vencrypt+tls+vnc";
203 case VNC_AUTH_VENCRYPT_TLSPLAIN:
204 return "vencrypt+tls+plain";
205 case VNC_AUTH_VENCRYPT_X509NONE:
206 return "vencrypt+x509+none";
207 case VNC_AUTH_VENCRYPT_X509VNC:
208 return "vencrypt+x509+vnc";
209 case VNC_AUTH_VENCRYPT_X509PLAIN:
210 return "vencrypt+x509+plain";
aliguori28a76be2009-03-06 20:27:40 +0000211 case VNC_AUTH_VENCRYPT_TLSSASL:
212 return "vencrypt+tls+sasl";
213 case VNC_AUTH_VENCRYPT_X509SASL:
214 return "vencrypt+x509+sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000215 default:
216 return "vencrypt";
217 }
218#else
219 return "vencrypt";
220#endif
aliguori2f9606b2009-03-06 20:27:28 +0000221 case VNC_AUTH_SASL:
aliguori28a76be2009-03-06 20:27:40 +0000222 return "sasl";
aliguori1ff7df12009-03-06 20:27:05 +0000223 }
224 return "unknown";
225}
226
Luiz Capitulinoa7789382010-01-14 14:50:53 -0200227static int vnc_server_info_put(QDict *qdict)
228{
229 if (vnc_server_addr_put(qdict, vnc_display->lsock) < 0) {
230 return -1;
231 }
232
233 qdict_put(qdict, "auth", qstring_from_str(vnc_auth_name(vnc_display)));
234 return 0;
235}
236
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200237static void vnc_client_cache_auth(VncState *client)
aliguori1ff7df12009-03-06 20:27:05 +0000238{
Blue Swirl2ded6ad2010-10-13 18:38:08 +0000239#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200240 QDict *qdict;
Blue Swirl2ded6ad2010-10-13 18:38:08 +0000241#endif
aliguori1ff7df12009-03-06 20:27:05 +0000242
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200243 if (!client->info) {
244 return;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200245 }
aliguori1263b7d2009-03-06 20:27:32 +0000246
Blue Swirl2ded6ad2010-10-13 18:38:08 +0000247#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200248 qdict = qobject_to_qdict(client->info);
Blue Swirl2ded6ad2010-10-13 18:38:08 +0000249#endif
Luiz Capitulino4a80dba2010-01-14 14:50:56 -0200250
aliguori1263b7d2009-03-06 20:27:32 +0000251#ifdef CONFIG_VNC_TLS
252 if (client->tls.session &&
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200253 client->tls.dname) {
254 qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname));
255 }
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) {
Luiz Capitulino76825062010-01-14 14:50:54 -0200260 qdict_put(qdict, "sasl_username",
261 qstring_from_str(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{
268 QDict *qdict;
269
270 qdict = qdict_new();
271 if (vnc_qdict_remote_addr(qdict, client->csock) < 0) {
272 QDECREF(qdict);
273 /* XXX: how to report the error? */
274 return;
275 }
276
277 client->info = QOBJECT(qdict);
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200278}
279
Luiz Capitulino586153d2010-01-14 14:50:57 -0200280static void vnc_qmp_event(VncState *vs, MonitorEvent event)
281{
282 QDict *server;
283 QObject *data;
284
285 if (!vs->info) {
286 return;
287 }
288
289 server = qdict_new();
290 if (vnc_server_info_put(server) < 0) {
291 QDECREF(server);
292 return;
293 }
294
295 data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
296 vs->info, QOBJECT(server));
297
298 monitor_protocol_event(event, data);
299
300 qobject_incref(vs->info);
301 qobject_decref(data);
302}
303
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200304static VncClientInfo *qmp_query_vnc_client(const VncState *client)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200305{
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200306 struct sockaddr_storage sa;
307 socklen_t salen = sizeof(sa);
308 char host[NI_MAXHOST];
309 char serv[NI_MAXSERV];
310 VncClientInfo *info;
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200311
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200312 if (getpeername(client->csock, (struct sockaddr *)&sa, &salen) < 0) {
313 return NULL;
314 }
315
316 if (getnameinfo((struct sockaddr *)&sa, salen,
317 host, sizeof(host),
318 serv, sizeof(serv),
319 NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
320 return NULL;
321 }
322
323 info = g_malloc0(sizeof(*info));
324 info->host = g_strdup(host);
325 info->service = g_strdup(serv);
326 info->family = g_strdup(inet_strfamily(sa.ss_family));
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200327
328#ifdef CONFIG_VNC_TLS
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200329 if (client->tls.session && client->tls.dname) {
330 info->has_x509_dname = true;
331 info->x509_dname = g_strdup(client->tls.dname);
332 }
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200333#endif
334#ifdef CONFIG_VNC_SASL
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200335 if (client->sasl.conn && client->sasl.username) {
336 info->has_sasl_username = true;
337 info->sasl_username = g_strdup(client->sasl.username);
338 }
aliguori1263b7d2009-03-06 20:27:32 +0000339#endif
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200340
341 return info;
aliguori1ff7df12009-03-06 20:27:05 +0000342}
343
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200344VncInfo *qmp_query_vnc(Error **errp)
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200345{
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200346 VncInfo *info = g_malloc0(sizeof(*info));
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200347
aliguori1ff7df12009-03-06 20:27:05 +0000348 if (vnc_display == NULL || vnc_display->display == NULL) {
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200349 info->enabled = false;
aliguori1ff7df12009-03-06 20:27:05 +0000350 } else {
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200351 VncClientInfoList *cur_item = NULL;
352 struct sockaddr_storage sa;
353 socklen_t salen = sizeof(sa);
354 char host[NI_MAXHOST];
355 char serv[NI_MAXSERV];
Amit Shah41b4bef2010-02-05 16:34:05 +0530356 VncState *client;
bellarda9ce8592007-02-05 20:20:30 +0000357
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200358 info->enabled = true;
359
360 /* for compatibility with the original command */
361 info->has_clients = true;
362
Amit Shah41b4bef2010-02-05 16:34:05 +0530363 QTAILQ_FOREACH(client, &vnc_display->clients, next) {
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200364 VncClientInfoList *cinfo = g_malloc0(sizeof(*info));
365 cinfo->value = qmp_query_vnc_client(client);
366
367 /* XXX: waiting for the qapi to support GSList */
368 if (!cur_item) {
369 info->clients = cur_item = cinfo;
370 } else {
371 cur_item->next = cinfo;
372 cur_item = cinfo;
aliguori1ff7df12009-03-06 20:27:05 +0000373 }
Luiz Capitulinod96fd292009-12-10 17:16:10 -0200374 }
375
Paolo Bonzini417b0b82012-10-10 14:30:58 +0200376 if (vnc_display->lsock == -1) {
377 return info;
378 }
379
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200380 if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa,
381 &salen) == -1) {
382 error_set(errp, QERR_UNDEFINED_ERROR);
383 goto out_error;
aliguori1ff7df12009-03-06 20:27:05 +0000384 }
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200385
386 if (getnameinfo((struct sockaddr *)&sa, salen,
387 host, sizeof(host),
388 serv, sizeof(serv),
389 NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
390 error_set(errp, QERR_UNDEFINED_ERROR);
391 goto out_error;
392 }
393
394 info->has_host = true;
395 info->host = g_strdup(host);
396
397 info->has_service = true;
398 info->service = g_strdup(serv);
399
400 info->has_family = true;
401 info->family = g_strdup(inet_strfamily(sa.ss_family));
402
403 info->has_auth = true;
404 info->auth = g_strdup(vnc_auth_name(vnc_display));
bellarda9ce8592007-02-05 20:20:30 +0000405 }
Luiz Capitulino2b54aa82011-10-17 16:41:22 -0200406
407 return info;
408
409out_error:
410 qapi_free_VncInfo(info);
411 return NULL;
bellarda9ce8592007-02-05 20:20:30 +0000412}
413
bellard24236862006-04-30 21:28:36 +0000414/* TODO
415 1) Get the queue working for IO.
416 2) there is some weirdness when using the -S option (the screen is grey
417 and not totally invalidated
418 3) resolutions > 1024
419*/
420
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100421static int vnc_update_client(VncState *vs, int has_dirty, bool sync);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200422static void vnc_disconnect_start(VncState *vs);
bellard24236862006-04-30 21:28:36 +0000423
aliguori753b4052009-02-16 14:59:30 +0000424static void vnc_colordepth(VncState *vs);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100425static void framebuffer_update_request(VncState *vs, int incremental,
426 int x_position, int y_position,
427 int w, int h);
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +0100428static void vnc_refresh(DisplayChangeListener *dcl);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100429static int vnc_refresh_server_surface(VncDisplay *vd);
aliguori7eac3a82008-09-15 16:03:41 +0000430
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100431static void vnc_dpy_update(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100432 int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000433{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +0100434 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100435 struct VncSurface *s = &vd->guest;
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100436 int width = surface_width(vd->ds);
437 int height = surface_height(vd->ds);
bellard24236862006-04-30 21:28:36 +0000438
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 Lieven91937222014-01-08 10:08:37 +0100450 bitmap_set(s->dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
451 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
Corentin Chary70a45682010-05-03 14:31:34 +0200455void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
456 int32_t encoding)
bellard24236862006-04-30 21:28:36 +0000457{
458 vnc_write_u16(vs, x);
459 vnc_write_u16(vs, y);
460 vnc_write_u16(vs, w);
461 vnc_write_u16(vs, h);
462
463 vnc_write_s32(vs, encoding);
464}
465
aliguori2f9606b2009-03-06 20:27:28 +0000466void buffer_reserve(Buffer *buffer, size_t len)
aliguori89064282009-02-02 15:58:47 +0000467{
468 if ((buffer->capacity - buffer->offset) < len) {
aliguori28a76be2009-03-06 20:27:40 +0000469 buffer->capacity += (len + 1024);
Anthony Liguori7267c092011-08-20 22:09:37 -0500470 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
aliguori28a76be2009-03-06 20:27:40 +0000471 if (buffer->buffer == NULL) {
472 fprintf(stderr, "vnc: out of memory\n");
473 exit(1);
474 }
aliguori89064282009-02-02 15:58:47 +0000475 }
476}
477
Blue Swirl71a8cde2012-10-28 11:04:48 +0000478static int buffer_empty(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000479{
480 return buffer->offset == 0;
481}
482
Tim Hardeck7536ee42013-01-21 11:04:44 +0100483uint8_t *buffer_end(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000484{
485 return buffer->buffer + buffer->offset;
486}
487
aliguori2f9606b2009-03-06 20:27:28 +0000488void buffer_reset(Buffer *buffer)
aliguori89064282009-02-02 15:58:47 +0000489{
aliguori28a76be2009-03-06 20:27:40 +0000490 buffer->offset = 0;
aliguori89064282009-02-02 15:58:47 +0000491}
492
Corentin Chary5d418e32010-05-19 09:24:07 +0200493void buffer_free(Buffer *buffer)
494{
Anthony Liguori7267c092011-08-20 22:09:37 -0500495 g_free(buffer->buffer);
Corentin Chary5d418e32010-05-19 09:24:07 +0200496 buffer->offset = 0;
497 buffer->capacity = 0;
498 buffer->buffer = NULL;
499}
500
aliguori2f9606b2009-03-06 20:27:28 +0000501void buffer_append(Buffer *buffer, const void *data, size_t len)
aliguori89064282009-02-02 15:58:47 +0000502{
503 memcpy(buffer->buffer + buffer->offset, data, len);
504 buffer->offset += len;
505}
506
Tim Hardeck32ed2682013-01-21 11:04:43 +0100507void buffer_advance(Buffer *buf, size_t len)
508{
509 memmove(buf->buffer, buf->buffer + len,
510 (buf->offset - len));
511 buf->offset -= len;
512}
513
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200514static void vnc_desktop_resize(VncState *vs)
515{
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100516 DisplaySurface *ds = vs->vd->ds;
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200517
518 if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
519 return;
520 }
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100521 if (vs->client_width == surface_width(ds) &&
522 vs->client_height == surface_height(ds)) {
Gerd Hoffmann1d4b6382010-05-25 18:25:20 +0200523 return;
524 }
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100525 vs->client_width = surface_width(ds);
526 vs->client_height = surface_height(ds);
Corentin Charybd023f92010-07-07 20:58:02 +0200527 vnc_lock_output(vs);
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200528 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
529 vnc_write_u8(vs, 0);
530 vnc_write_u16(vs, 1); /* number of rects */
Gerd Hoffmann5862d192010-05-25 18:25:18 +0200531 vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200532 VNC_ENCODING_DESKTOPRESIZE);
Corentin Charybd023f92010-07-07 20:58:02 +0200533 vnc_unlock_output(vs);
Gerd Hoffmann621aaeb2010-05-25 18:25:16 +0200534 vnc_flush(vs);
535}
536
Corentin Charybd023f92010-07-07 20:58:02 +0200537static void vnc_abort_display_jobs(VncDisplay *vd)
538{
539 VncState *vs;
540
541 QTAILQ_FOREACH(vs, &vd->clients, next) {
542 vnc_lock_output(vs);
543 vs->abort = true;
544 vnc_unlock_output(vs);
545 }
546 QTAILQ_FOREACH(vs, &vd->clients, next) {
547 vnc_jobs_join(vs);
548 }
549 QTAILQ_FOREACH(vs, &vd->clients, next) {
550 vnc_lock_output(vs);
551 vs->abort = false;
552 vnc_unlock_output(vs);
553 }
554}
Corentin Charybd023f92010-07-07 20:58:02 +0200555
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200556int vnc_server_fb_stride(VncDisplay *vd)
557{
558 return pixman_image_get_stride(vd->server);
559}
560
561void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
562{
563 uint8_t *ptr;
564
565 ptr = (uint8_t *)pixman_image_get_data(vd->server);
566 ptr += y * vnc_server_fb_stride(vd);
567 ptr += x * VNC_SERVER_FB_BYTES;
568 return ptr;
569}
Peter Lieven12b316d2014-01-08 10:08:35 +0100570/* this sets only the visible pixels of a dirty bitmap */
571#define VNC_SET_VISIBLE_PIXELS_DIRTY(bitmap, w, h) {\
572 int y;\
573 memset(bitmap, 0x00, sizeof(bitmap));\
574 for (y = 0; y < h; y++) {\
575 bitmap_set(bitmap[y], 0,\
576 DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));\
577 } \
578 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200579
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;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100585
Corentin Charybd023f92010-07-07 20:58:02 +0200586 vnc_abort_display_jobs(vd);
587
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100588 /* server surface */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200589 qemu_pixman_image_unref(vd->server);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100590 vd->ds = surface;
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200591 vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100592 surface_width(vd->ds),
593 surface_height(vd->ds),
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200594 NULL, 0);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100595
596 /* guest surface */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200597#if 0 /* FIXME */
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100598 if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
599 console_color_init(ds);
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200600#endif
601 qemu_pixman_image_unref(vd->guest.fb);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +0100602 vd->guest.fb = pixman_image_ref(surface->image);
603 vd->guest.format = surface->format;
Peter Lieven12b316d2014-01-08 10:08:35 +0100604 VNC_SET_VISIBLE_PIXELS_DIRTY(vd->guest.dirty,
605 surface_width(vd->ds),
606 surface_height(vd->ds));
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100607
Amit Shah41b4bef2010-02-05 16:34:05 +0530608 QTAILQ_FOREACH(vs, &vd->clients, next) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100609 vnc_colordepth(vs);
Gerd Hoffmann1d4b6382010-05-25 18:25:20 +0200610 vnc_desktop_resize(vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200611 if (vs->vd->cursor) {
612 vnc_cursor_define(vs);
613 }
Peter Lieven12b316d2014-01-08 10:08:35 +0100614 VNC_SET_VISIBLE_PIXELS_DIRTY(vs->dirty,
615 surface_width(vd->ds),
616 surface_height(vd->ds));
aliguori753b4052009-02-16 14:59:30 +0000617 }
618}
619
bellard35127792006-05-14 18:11:49 +0000620/* fastest code */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200621static void vnc_write_pixels_copy(VncState *vs,
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200622 void *pixels, int size)
bellard35127792006-05-14 18:11:49 +0000623{
624 vnc_write(vs, pixels, size);
625}
626
627/* slowest but generic code. */
Corentin Chary70a45682010-05-03 14:31:34 +0200628void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
bellard35127792006-05-14 18:11:49 +0000629{
aliguori7eac3a82008-09-15 16:03:41 +0000630 uint8_t r, g, b;
bellard35127792006-05-14 18:11:49 +0000631
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200632#if VNC_SERVER_FB_FORMAT == PIXMAN_FORMAT(32, PIXMAN_TYPE_ARGB, 0, 8, 8, 8)
633 r = (((v & 0x00ff0000) >> 16) << vs->client_pf.rbits) >> 8;
634 g = (((v & 0x0000ff00) >> 8) << vs->client_pf.gbits) >> 8;
635 b = (((v & 0x000000ff) >> 0) << vs->client_pf.bbits) >> 8;
636#else
637# error need some bits here if you change VNC_SERVER_FB_FORMAT
638#endif
639 v = (r << vs->client_pf.rshift) |
640 (g << vs->client_pf.gshift) |
641 (b << vs->client_pf.bshift);
642 switch (vs->client_pf.bytes_per_pixel) {
bellard35127792006-05-14 18:11:49 +0000643 case 1:
644 buf[0] = v;
645 break;
646 case 2:
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200647 if (vs->client_be) {
bellard35127792006-05-14 18:11:49 +0000648 buf[0] = v >> 8;
649 buf[1] = v;
650 } else {
651 buf[1] = v >> 8;
652 buf[0] = v;
653 }
654 break;
655 default:
656 case 4:
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200657 if (vs->client_be) {
bellard35127792006-05-14 18:11:49 +0000658 buf[0] = v >> 24;
659 buf[1] = v >> 16;
660 buf[2] = v >> 8;
661 buf[3] = v;
662 } else {
663 buf[3] = v >> 24;
664 buf[2] = v >> 16;
665 buf[1] = v >> 8;
666 buf[0] = v;
667 }
668 break;
669 }
670}
671
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200672static void vnc_write_pixels_generic(VncState *vs,
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200673 void *pixels1, int size)
bellard35127792006-05-14 18:11:49 +0000674{
bellard35127792006-05-14 18:11:49 +0000675 uint8_t buf[4];
bellard35127792006-05-14 18:11:49 +0000676
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200677 if (VNC_SERVER_FB_BYTES == 4) {
aliguori7eac3a82008-09-15 16:03:41 +0000678 uint32_t *pixels = pixels1;
679 int n, i;
680 n = size >> 2;
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200681 for (i = 0; i < n; i++) {
aliguori7eac3a82008-09-15 16:03:41 +0000682 vnc_convert_pixel(vs, buf, pixels[i]);
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200683 vnc_write(vs, buf, vs->client_pf.bytes_per_pixel);
aliguori7eac3a82008-09-15 16:03:41 +0000684 }
bellard35127792006-05-14 18:11:49 +0000685 }
686}
687
Corentin Charya8852112010-05-19 09:24:09 +0200688int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000689{
690 int i;
ths60fe76f2007-12-16 03:02:09 +0000691 uint8_t *row;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100692 VncDisplay *vd = vs->vd;
bellard24236862006-04-30 21:28:36 +0000693
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200694 row = vnc_server_fb_ptr(vd, x, y);
bellard24236862006-04-30 21:28:36 +0000695 for (i = 0; i < h; i++) {
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200696 vs->write_pixels(vs, row, w * VNC_SERVER_FB_BYTES);
697 row += vnc_server_fb_stride(vd);
bellard24236862006-04-30 21:28:36 +0000698 }
Corentin Charya8852112010-05-19 09:24:09 +0200699 return 1;
bellard24236862006-04-30 21:28:36 +0000700}
701
Corentin Charybd023f92010-07-07 20:58:02 +0200702int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
bellard24236862006-04-30 21:28:36 +0000703{
Corentin Charya8852112010-05-19 09:24:09 +0200704 int n = 0;
705
aliguorifb437312009-02-02 15:58:43 +0000706 switch(vs->vnc_encoding) {
aliguori28a76be2009-03-06 20:27:40 +0000707 case VNC_ENCODING_ZLIB:
Corentin Charya8852112010-05-19 09:24:09 +0200708 n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
aliguori28a76be2009-03-06 20:27:40 +0000709 break;
710 case VNC_ENCODING_HEXTILE:
711 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
Corentin Charya8852112010-05-19 09:24:09 +0200712 n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
aliguori28a76be2009-03-06 20:27:40 +0000713 break;
Corentin Chary380282b2010-05-19 09:24:10 +0200714 case VNC_ENCODING_TIGHT:
715 n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
716 break;
Corentin Charyefe556a2010-07-07 20:57:56 +0200717 case VNC_ENCODING_TIGHT_PNG:
718 n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
719 break;
Corentin Chary148954f2011-02-04 09:06:01 +0100720 case VNC_ENCODING_ZRLE:
721 n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
722 break;
723 case VNC_ENCODING_ZYWRLE:
724 n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
725 break;
aliguori28a76be2009-03-06 20:27:40 +0000726 default:
727 vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
Corentin Charya8852112010-05-19 09:24:09 +0200728 n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
aliguori28a76be2009-03-06 20:27:40 +0000729 break;
aliguorifb437312009-02-02 15:58:43 +0000730 }
Corentin Charya8852112010-05-19 09:24:09 +0200731 return n;
bellard24236862006-04-30 21:28:36 +0000732}
733
aliguori753b4052009-02-16 14:59:30 +0000734static 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 +0000735{
Gerd Hoffmann3e28c9a2009-07-27 17:10:48 +0200736 /* send bitblit op to the vnc client */
Corentin Charybd023f92010-07-07 20:58:02 +0200737 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +0100738 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
bellard24236862006-04-30 21:28:36 +0000739 vnc_write_u8(vs, 0);
740 vnc_write_u16(vs, 1); /* number of rects */
aliguori29fa4ed2009-02-02 15:58:29 +0000741 vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
bellard24236862006-04-30 21:28:36 +0000742 vnc_write_u16(vs, src_x);
743 vnc_write_u16(vs, src_y);
Corentin Charybd023f92010-07-07 20:58:02 +0200744 vnc_unlock_output(vs);
bellard24236862006-04-30 21:28:36 +0000745 vnc_flush(vs);
746}
747
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100748static void vnc_dpy_copy(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100749 int src_x, int src_y,
750 int dst_x, int dst_y, int w, int h)
aliguori753b4052009-02-16 14:59:30 +0000751{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +0100752 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200753 VncState *vs, *vn;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100754 uint8_t *src_row;
755 uint8_t *dst_row;
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200756 int i, x, y, pitch, inc, w_lim, s;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100757 int cmp_bytes;
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200758
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100759 vnc_refresh_server_surface(vd);
Amit Shah41b4bef2010-02-05 16:34:05 +0530760 QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200761 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
762 vs->force_update = 1;
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100763 vnc_update_client(vs, 1, true);
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200764 /* vs might be free()ed here */
765 }
766 }
767
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100768 /* do bitblit op on the local surface too */
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200769 pitch = vnc_server_fb_stride(vd);
770 src_row = vnc_server_fb_ptr(vd, src_x, src_y);
771 dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y);
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100772 y = dst_y;
773 inc = 1;
774 if (dst_y > src_y) {
775 /* copy backwards */
776 src_row += pitch * (h-1);
777 dst_row += pitch * (h-1);
778 pitch = -pitch;
779 y = dst_y + h - 1;
780 inc = -1;
781 }
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100782 w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
783 if (w_lim < 0) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100784 w_lim = w;
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100785 } else {
786 w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT);
787 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100788 for (i = 0; i < h; i++) {
789 for (x = 0; x <= w_lim;
790 x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
791 if (x == w_lim) {
792 if ((s = w - w_lim) == 0)
793 break;
794 } else if (!x) {
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100795 s = (VNC_DIRTY_PIXELS_PER_BIT -
796 (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100797 s = MIN(s, w_lim);
798 } else {
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100799 s = VNC_DIRTY_PIXELS_PER_BIT;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100800 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200801 cmp_bytes = s * VNC_SERVER_FB_BYTES;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100802 if (memcmp(src_row, dst_row, cmp_bytes) == 0)
803 continue;
804 memmove(dst_row, src_row, cmp_bytes);
Amit Shah41b4bef2010-02-05 16:34:05 +0530805 QTAILQ_FOREACH(vs, &vd->clients, next) {
806 if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
Peter Lievenb4c85dd2014-01-08 10:08:33 +0100807 set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT),
808 vs->dirty[y]);
Amit Shah41b4bef2010-02-05 16:34:05 +0530809 }
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100810 }
811 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200812 src_row += pitch - w * VNC_SERVER_FB_BYTES;
813 dst_row += pitch - w * VNC_SERVER_FB_BYTES;
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100814 y += inc;
815 }
816
Amit Shah41b4bef2010-02-05 16:34:05 +0530817 QTAILQ_FOREACH(vs, &vd->clients, next) {
818 if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
aliguori753b4052009-02-16 14:59:30 +0000819 vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
Amit Shah41b4bef2010-02-05 16:34:05 +0530820 }
aliguori753b4052009-02-16 14:59:30 +0000821 }
822}
823
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100824static void vnc_mouse_set(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100825 int x, int y, int visible)
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200826{
827 /* can we ask the client(s) to move the pointer ??? */
828}
829
830static int vnc_cursor_define(VncState *vs)
831{
832 QEMUCursor *c = vs->vd->cursor;
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200833 int isize;
834
835 if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
Corentin Charyd01f9592010-07-07 20:58:03 +0200836 vnc_lock_output(vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200837 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
838 vnc_write_u8(vs, 0); /* padding */
839 vnc_write_u16(vs, 1); /* # of rects */
840 vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
841 VNC_ENCODING_RICH_CURSOR);
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200842 isize = c->width * c->height * vs->client_pf.bytes_per_pixel;
843 vnc_write_pixels_generic(vs, c->data, isize);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200844 vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
Corentin Charyd01f9592010-07-07 20:58:03 +0200845 vnc_unlock_output(vs);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200846 return 0;
847 }
848 return -1;
849}
850
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100851static void vnc_dpy_cursor_define(DisplayChangeListener *dcl,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +0100852 QEMUCursor *c)
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200853{
854 VncDisplay *vd = vnc_display;
855 VncState *vs;
856
857 cursor_put(vd->cursor);
Anthony Liguori7267c092011-08-20 22:09:37 -0500858 g_free(vd->cursor_mask);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200859
860 vd->cursor = c;
861 cursor_get(vd->cursor);
862 vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
Anthony Liguori7267c092011-08-20 22:09:37 -0500863 vd->cursor_mask = g_malloc0(vd->cursor_msize);
Gerd Hoffmannd467b672010-05-21 11:54:34 +0200864 cursor_get_mono_mask(c, 0, vd->cursor_mask);
865
866 QTAILQ_FOREACH(vs, &vd->clients, next) {
867 vnc_cursor_define(vs);
868 }
869}
870
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100871static int find_and_clear_dirty_height(struct VncState *vs,
Corentin Chary6c71a532011-02-04 09:06:06 +0100872 int y, int last_x, int x, int height)
bellard24236862006-04-30 21:28:36 +0000873{
874 int h;
875
Corentin Chary6c71a532011-02-04 09:06:06 +0100876 for (h = 1; h < (height - y); h++) {
Corentin Charybc2429b2011-02-04 09:06:05 +0100877 if (!test_bit(last_x, vs->dirty[y + h])) {
aliguori28a76be2009-03-06 20:27:40 +0000878 break;
Corentin Charybc2429b2011-02-04 09:06:05 +0100879 }
Peter Lieven863d7c92014-01-08 10:08:36 +0100880 bitmap_clear(vs->dirty[y + h], last_x, x - last_x);
bellard24236862006-04-30 21:28:36 +0000881 }
882
883 return h;
884}
885
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100886static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
bellard24236862006-04-30 21:28:36 +0000887{
bellard24236862006-04-30 21:28:36 +0000888 if (vs->need_update && vs->csock != -1) {
Stefano Stabellini1fc62412009-08-03 10:54:32 +0100889 VncDisplay *vd = vs->vd;
Corentin Charybd023f92010-07-07 20:58:02 +0200890 VncJob *job;
aliguori28a76be2009-03-06 20:27:40 +0000891 int y;
Peter Lieven2f487a3d2014-03-17 18:38:58 +0100892 int height, width;
Corentin Charybd023f92010-07-07 20:58:02 +0200893 int n = 0;
894
Stefano Stabellini703bc682009-08-03 10:54:05 +0100895 if (vs->output.offset && !vs->audio_cap && !vs->force_update)
aliguoric522d0e2009-03-20 15:59:24 +0000896 /* kernel send buffers are full -> drop frames to throttle */
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100897 return 0;
balroga0ecfb72008-01-13 23:51:53 +0000898
Stefano Stabellini703bc682009-08-03 10:54:05 +0100899 if (!has_dirty && !vs->audio_cap && !vs->force_update)
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100900 return 0;
bellard24236862006-04-30 21:28:36 +0000901
aliguori6baebed2009-03-20 15:59:14 +0000902 /*
903 * Send screen updates to the vnc client using the server
904 * surface and server dirty map. guest surface updates
905 * happening in parallel don't disturb us, the next pass will
906 * send them to the client.
907 */
Corentin Charybd023f92010-07-07 20:58:02 +0200908 job = vnc_job_new(vs);
bellard24236862006-04-30 21:28:36 +0000909
Gerd Hoffmann9f649162012-10-10 13:29:43 +0200910 height = MIN(pixman_image_get_height(vd->server), vs->client_height);
Peter Lieven2f487a3d2014-03-17 18:38:58 +0100911 width = MIN(pixman_image_get_width(vd->server), vs->client_width);
Gerd Hoffmann847ce6a2010-05-25 18:25:19 +0200912
Peter Lieven12b316d2014-01-08 10:08:35 +0100913 y = 0;
914 for (;;) {
915 int x, h;
916 unsigned long x2;
917 unsigned long offset = find_next_bit((unsigned long *) &vs->dirty,
918 height * VNC_DIRTY_BPL(vs),
919 y * VNC_DIRTY_BPL(vs));
920 if (offset == height * VNC_DIRTY_BPL(vs)) {
921 /* no more dirty bits */
922 break;
aliguori28a76be2009-03-06 20:27:40 +0000923 }
Peter Lieven12b316d2014-01-08 10:08:35 +0100924 y = offset / VNC_DIRTY_BPL(vs);
925 x = offset % VNC_DIRTY_BPL(vs);
926 x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y],
927 VNC_DIRTY_BPL(vs), x);
928 bitmap_clear(vs->dirty[y], x, x2 - x);
929 h = find_and_clear_dirty_height(vs, y, x, x2, height);
Peter Lieven2f487a3d2014-03-17 18:38:58 +0100930 x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT);
931 if (x2 > x) {
932 n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y,
933 (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h);
934 }
aliguori28a76be2009-03-06 20:27:40 +0000935 }
Corentin Charybd023f92010-07-07 20:58:02 +0200936
937 vnc_job_push(job);
aliguoric522d0e2009-03-20 15:59:24 +0000938 vs->force_update = 0;
Corentin Charybd023f92010-07-07 20:58:02 +0200939 return n;
bellard24236862006-04-30 21:28:36 +0000940 }
bellard24236862006-04-30 21:28:36 +0000941
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100942 if (vs->csock == -1) {
Gerd Hoffmann198a0032009-06-16 14:19:48 +0200943 vnc_disconnect_finish(vs);
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +0100944 } else if (sync) {
945 vnc_jobs_join(vs);
946 }
Stefano Stabellini2430ffe2009-08-03 10:56:01 +0100947
948 return 0;
bellard24236862006-04-30 21:28:36 +0000949}
950
malc429a8ed2008-12-01 20:57:48 +0000951/* audio */
952static void audio_capture_notify(void *opaque, audcnotification_e cmd)
953{
954 VncState *vs = opaque;
955
956 switch (cmd) {
957 case AUD_CNOTIFY_DISABLE:
Corentin Charybd023f92010-07-07 20:58:02 +0200958 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +0100959 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
960 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
961 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
Corentin Charybd023f92010-07-07 20:58:02 +0200962 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +0000963 vnc_flush(vs);
964 break;
965
966 case AUD_CNOTIFY_ENABLE:
Corentin Charybd023f92010-07-07 20:58:02 +0200967 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +0100968 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
969 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
970 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
Corentin Charybd023f92010-07-07 20:58:02 +0200971 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +0000972 vnc_flush(vs);
973 break;
974 }
975}
976
977static void audio_capture_destroy(void *opaque)
978{
979}
980
981static void audio_capture(void *opaque, void *buf, int size)
982{
983 VncState *vs = opaque;
984
Corentin Charybd023f92010-07-07 20:58:02 +0200985 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +0100986 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
987 vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
988 vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
malc429a8ed2008-12-01 20:57:48 +0000989 vnc_write_u32(vs, size);
990 vnc_write(vs, buf, size);
Corentin Charybd023f92010-07-07 20:58:02 +0200991 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +0000992 vnc_flush(vs);
993}
994
995static void audio_add(VncState *vs)
996{
997 struct audio_capture_ops ops;
998
999 if (vs->audio_cap) {
Cole Robinson027a79c2014-03-21 19:42:21 -04001000 error_report("audio already running");
malc429a8ed2008-12-01 20:57:48 +00001001 return;
1002 }
1003
1004 ops.notify = audio_capture_notify;
1005 ops.destroy = audio_capture_destroy;
1006 ops.capture = audio_capture;
1007
malc1a7dafc2009-05-14 03:11:35 +04001008 vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
malc429a8ed2008-12-01 20:57:48 +00001009 if (!vs->audio_cap) {
Cole Robinson027a79c2014-03-21 19:42:21 -04001010 error_report("Failed to add audio capture");
malc429a8ed2008-12-01 20:57:48 +00001011 }
1012}
1013
1014static void audio_del(VncState *vs)
1015{
1016 if (vs->audio_cap) {
1017 AUD_del_capture(vs->audio_cap, vs);
1018 vs->audio_cap = NULL;
1019 }
1020}
1021
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001022static void vnc_disconnect_start(VncState *vs)
1023{
1024 if (vs->csock == -1)
1025 return;
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01001026 vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001027 qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
1028 closesocket(vs->csock);
1029 vs->csock = -1;
1030}
1031
Tim Hardeck7536ee42013-01-21 11:04:44 +01001032void vnc_disconnect_finish(VncState *vs)
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001033{
Corentin Chary7d964c92011-02-04 09:05:56 +01001034 int i;
1035
Corentin Charybd023f92010-07-07 20:58:02 +02001036 vnc_jobs_join(vs); /* Wait encoding jobs */
1037
1038 vnc_lock_output(vs);
Luiz Capitulino0d72f3d2010-01-14 14:50:58 -02001039 vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED);
1040
Corentin Chary5d418e32010-05-19 09:24:07 +02001041 buffer_free(&vs->input);
1042 buffer_free(&vs->output);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001043#ifdef CONFIG_VNC_WS
1044 buffer_free(&vs->ws_input);
1045 buffer_free(&vs->ws_output);
1046#endif /* CONFIG_VNC_WS */
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02001047
1048 qobject_decref(vs->info);
1049
Corentin Chary161c4f22010-05-19 09:24:08 +02001050 vnc_zlib_clear(vs);
Corentin Chary380282b2010-05-19 09:24:10 +02001051 vnc_tight_clear(vs);
Corentin Chary148954f2011-02-04 09:06:01 +01001052 vnc_zrle_clear(vs);
Corentin Chary161c4f22010-05-19 09:24:08 +02001053
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001054#ifdef CONFIG_VNC_TLS
1055 vnc_tls_client_cleanup(vs);
1056#endif /* CONFIG_VNC_TLS */
1057#ifdef CONFIG_VNC_SASL
1058 vnc_sasl_client_cleanup(vs);
1059#endif /* CONFIG_VNC_SASL */
1060 audio_del(vs);
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001061 vnc_release_modifiers(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001062
Tim Hardeck6fd8e792013-01-21 11:04:45 +01001063 if (vs->initialized) {
1064 QTAILQ_REMOVE(&vs->vd->clients, vs, next);
1065 qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
1066 }
Amit Shah41b4bef2010-02-05 16:34:05 +05301067
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01001068 if (vs->vd->lock_key_sync)
1069 qemu_remove_led_event_handler(vs->led);
Corentin Charybd023f92010-07-07 20:58:02 +02001070 vnc_unlock_output(vs);
1071
Corentin Charybd023f92010-07-07 20:58:02 +02001072 qemu_mutex_destroy(&vs->output_mutex);
Tim Hardeck6fd8e792013-01-21 11:04:45 +01001073 if (vs->bh != NULL) {
1074 qemu_bh_delete(vs->bh);
1075 }
Corentin Chary175b2a62012-03-14 07:58:47 +01001076 buffer_free(&vs->jobs_buffer);
Corentin Chary175b2a62012-03-14 07:58:47 +01001077
Corentin Chary7d964c92011-02-04 09:05:56 +01001078 for (i = 0; i < VNC_STAT_ROWS; ++i) {
Anthony Liguori7267c092011-08-20 22:09:37 -05001079 g_free(vs->lossy_rect[i]);
Corentin Chary7d964c92011-02-04 09:05:56 +01001080 }
Anthony Liguori7267c092011-08-20 22:09:37 -05001081 g_free(vs->lossy_rect);
1082 g_free(vs);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001083}
aliguori2f9606b2009-03-06 20:27:28 +00001084
1085int vnc_client_io_error(VncState *vs, int ret, int last_errno)
bellard24236862006-04-30 21:28:36 +00001086{
1087 if (ret == 0 || ret == -1) {
balrogea01e5f2008-04-24 23:40:55 +00001088 if (ret == -1) {
1089 switch (last_errno) {
1090 case EINTR:
1091 case EAGAIN:
1092#ifdef _WIN32
1093 case WSAEWOULDBLOCK:
1094#endif
1095 return 0;
1096 default:
1097 break;
1098 }
1099 }
bellard24236862006-04-30 21:28:36 +00001100
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001101 VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
1102 ret, ret < 0 ? last_errno : 0);
1103 vnc_disconnect_start(vs);
aliguori6baebed2009-03-20 15:59:14 +00001104
aliguori28a76be2009-03-06 20:27:40 +00001105 return 0;
bellard24236862006-04-30 21:28:36 +00001106 }
1107 return ret;
1108}
1109
aliguori5fb6c7a2009-03-06 20:27:23 +00001110
1111void vnc_client_error(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001112{
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001113 VNC_DEBUG("Closing down client sock: protocol error\n");
1114 vnc_disconnect_start(vs);
bellard24236862006-04-30 21:28:36 +00001115}
1116
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001117#ifdef CONFIG_VNC_TLS
1118static long vnc_client_write_tls(gnutls_session_t *session,
1119 const uint8_t *data,
1120 size_t datalen)
1121{
1122 long ret = gnutls_write(*session, data, datalen);
1123 if (ret < 0) {
1124 if (ret == GNUTLS_E_AGAIN) {
1125 errno = EAGAIN;
1126 } else {
1127 errno = EIO;
1128 }
1129 ret = -1;
1130 }
1131 return ret;
1132}
1133#endif /* CONFIG_VNC_TLS */
aliguori2f9606b2009-03-06 20:27:28 +00001134
1135/*
1136 * Called to write a chunk of data to the client socket. The data may
1137 * be the raw data, or may have already been encoded by SASL.
1138 * The data will be written either straight onto the socket, or
1139 * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1140 *
1141 * NB, it is theoretically possible to have 2 layers of encryption,
1142 * both SASL, and this TLS layer. It is highly unlikely in practice
1143 * though, since SASL encryption will typically be a no-op if TLS
1144 * is active
1145 *
1146 * Returns the number of bytes written, which may be less than
1147 * the requested 'datalen' if the socket would block. Returns
1148 * -1 on error, and disconnects the client socket.
1149 */
1150long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001151{
bellardceb5caa2006-05-03 21:18:59 +00001152 long ret;
blueswir1eb38c522008-09-06 17:47:39 +00001153#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +00001154 if (vs->tls.session) {
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001155 ret = vnc_client_write_tls(&vs->tls.session, data, datalen);
1156 } else {
1157#ifdef CONFIG_VNC_WS
1158 if (vs->ws_tls.session) {
1159 ret = vnc_client_write_tls(&vs->ws_tls.session, data, datalen);
1160 } else
1161#endif /* CONFIG_VNC_WS */
ths8d5d2d42007-08-25 01:37:51 +00001162#endif /* CONFIG_VNC_TLS */
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001163 {
1164 ret = send(vs->csock, (const void *)data, datalen, 0);
1165 }
1166#ifdef CONFIG_VNC_TLS
1167 }
1168#endif /* CONFIG_VNC_TLS */
aliguori23decc82009-03-20 15:59:18 +00001169 VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +00001170 return vnc_client_io_error(vs, ret, socket_error());
1171}
1172
1173
1174/*
1175 * Called to write buffered data to the client socket, when not
1176 * using any SASL SSF encryption layers. Will write as much data
1177 * as possible without blocking. If all buffered data is written,
1178 * will switch the FD poll() handler back to read monitoring.
1179 *
1180 * Returns the number of bytes written, which may be less than
1181 * the buffered output data if the socket would block. Returns
1182 * -1 on error, and disconnects the client socket.
1183 */
1184static long vnc_client_write_plain(VncState *vs)
1185{
1186 long ret;
1187
1188#ifdef CONFIG_VNC_SASL
aliguori23decc82009-03-20 15:59:18 +00001189 VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
aliguori2f9606b2009-03-06 20:27:28 +00001190 vs->output.buffer, vs->output.capacity, vs->output.offset,
1191 vs->sasl.waitWriteSSF);
1192
1193 if (vs->sasl.conn &&
1194 vs->sasl.runSSF &&
1195 vs->sasl.waitWriteSSF) {
1196 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
1197 if (ret)
1198 vs->sasl.waitWriteSSF -= ret;
1199 } else
1200#endif /* CONFIG_VNC_SASL */
1201 ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
bellard24236862006-04-30 21:28:36 +00001202 if (!ret)
aliguori2f9606b2009-03-06 20:27:28 +00001203 return 0;
bellard24236862006-04-30 21:28:36 +00001204
Tim Hardeck32ed2682013-01-21 11:04:43 +01001205 buffer_advance(&vs->output, ret);
bellard24236862006-04-30 21:28:36 +00001206
1207 if (vs->output.offset == 0) {
aliguori28a76be2009-03-06 20:27:40 +00001208 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
bellard24236862006-04-30 21:28:36 +00001209 }
aliguori2f9606b2009-03-06 20:27:28 +00001210
1211 return ret;
1212}
1213
1214
1215/*
1216 * First function called whenever there is data to be written to
1217 * the client socket. Will delegate actual work according to whether
1218 * SASL SSF layers are enabled (thus requiring encryption calls)
1219 */
Corentin Charybd023f92010-07-07 20:58:02 +02001220static void vnc_client_write_locked(void *opaque)
aliguori2f9606b2009-03-06 20:27:28 +00001221{
aliguori2f9606b2009-03-06 20:27:28 +00001222 VncState *vs = opaque;
1223
1224#ifdef CONFIG_VNC_SASL
1225 if (vs->sasl.conn &&
1226 vs->sasl.runSSF &&
Blue Swirl9678d952010-04-25 18:35:52 +00001227 !vs->sasl.waitWriteSSF) {
1228 vnc_client_write_sasl(vs);
1229 } else
aliguori2f9606b2009-03-06 20:27:28 +00001230#endif /* CONFIG_VNC_SASL */
Tim Hardeck7536ee42013-01-21 11:04:44 +01001231 {
1232#ifdef CONFIG_VNC_WS
1233 if (vs->encode_ws) {
1234 vnc_client_write_ws(vs);
1235 } else
1236#endif /* CONFIG_VNC_WS */
1237 {
1238 vnc_client_write_plain(vs);
1239 }
1240 }
bellard24236862006-04-30 21:28:36 +00001241}
1242
Corentin Charybd023f92010-07-07 20:58:02 +02001243void vnc_client_write(void *opaque)
1244{
1245 VncState *vs = opaque;
1246
1247 vnc_lock_output(vs);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001248 if (vs->output.offset
1249#ifdef CONFIG_VNC_WS
1250 || vs->ws_output.offset
1251#endif
1252 ) {
Corentin Charybd023f92010-07-07 20:58:02 +02001253 vnc_client_write_locked(opaque);
Yoshiaki Tamuraac711032010-08-20 19:10:41 +09001254 } else if (vs->csock != -1) {
Corentin Charybd023f92010-07-07 20:58:02 +02001255 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
1256 }
1257 vnc_unlock_output(vs);
1258}
1259
aliguori5fb6c7a2009-03-06 20:27:23 +00001260void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
bellard24236862006-04-30 21:28:36 +00001261{
1262 vs->read_handler = func;
1263 vs->read_handler_expect = expecting;
1264}
1265
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001266#ifdef CONFIG_VNC_TLS
1267static long vnc_client_read_tls(gnutls_session_t *session, uint8_t *data,
1268 size_t datalen)
1269{
1270 long ret = gnutls_read(*session, data, datalen);
1271 if (ret < 0) {
1272 if (ret == GNUTLS_E_AGAIN) {
1273 errno = EAGAIN;
1274 } else {
1275 errno = EIO;
1276 }
1277 ret = -1;
1278 }
1279 return ret;
1280}
1281#endif /* CONFIG_VNC_TLS */
aliguori2f9606b2009-03-06 20:27:28 +00001282
1283/*
1284 * Called to read a chunk of data from the client socket. The data may
1285 * be the raw data, or may need to be further decoded by SASL.
1286 * The data will be read either straight from to the socket, or
1287 * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1288 *
1289 * NB, it is theoretically possible to have 2 layers of encryption,
1290 * both SASL, and this TLS layer. It is highly unlikely in practice
1291 * though, since SASL encryption will typically be a no-op if TLS
1292 * is active
1293 *
1294 * Returns the number of bytes read, which may be less than
1295 * the requested 'datalen' if the socket would block. Returns
1296 * -1 on error, and disconnects the client socket.
1297 */
1298long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
bellard24236862006-04-30 21:28:36 +00001299{
bellardceb5caa2006-05-03 21:18:59 +00001300 long ret;
blueswir1eb38c522008-09-06 17:47:39 +00001301#ifdef CONFIG_VNC_TLS
aliguori5fb6c7a2009-03-06 20:27:23 +00001302 if (vs->tls.session) {
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001303 ret = vnc_client_read_tls(&vs->tls.session, data, datalen);
1304 } else {
1305#ifdef CONFIG_VNC_WS
1306 if (vs->ws_tls.session) {
1307 ret = vnc_client_read_tls(&vs->ws_tls.session, data, datalen);
1308 } else
1309#endif /* CONFIG_VNC_WS */
ths8d5d2d42007-08-25 01:37:51 +00001310#endif /* CONFIG_VNC_TLS */
Tim Hardeck0057a0d2013-04-23 16:33:01 +02001311 {
1312 ret = qemu_recv(vs->csock, data, datalen, 0);
1313 }
1314#ifdef CONFIG_VNC_TLS
1315 }
1316#endif /* CONFIG_VNC_TLS */
aliguori23decc82009-03-20 15:59:18 +00001317 VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
aliguori2f9606b2009-03-06 20:27:28 +00001318 return vnc_client_io_error(vs, ret, socket_error());
1319}
1320
1321
1322/*
1323 * Called to read data from the client socket to the input buffer,
1324 * when not using any SASL SSF encryption layers. Will read as much
1325 * data as possible without blocking.
1326 *
1327 * Returns the number of bytes read. Returns -1 on error, and
1328 * disconnects the client socket.
1329 */
1330static long vnc_client_read_plain(VncState *vs)
1331{
1332 int ret;
aliguori23decc82009-03-20 15:59:18 +00001333 VNC_DEBUG("Read plain %p size %zd offset %zd\n",
aliguori2f9606b2009-03-06 20:27:28 +00001334 vs->input.buffer, vs->input.capacity, vs->input.offset);
1335 buffer_reserve(&vs->input, 4096);
1336 ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
1337 if (!ret)
1338 return 0;
1339 vs->input.offset += ret;
1340 return ret;
1341}
1342
Corentin Chary175b2a62012-03-14 07:58:47 +01001343static void vnc_jobs_bh(void *opaque)
1344{
1345 VncState *vs = opaque;
1346
1347 vnc_jobs_consume_buffer(vs);
1348}
aliguori2f9606b2009-03-06 20:27:28 +00001349
1350/*
1351 * First function called whenever there is more data to be read from
1352 * the client socket. Will delegate actual work according to whether
1353 * SASL SSF layers are enabled (thus requiring decryption calls)
1354 */
1355void vnc_client_read(void *opaque)
1356{
1357 VncState *vs = opaque;
1358 long ret;
1359
1360#ifdef CONFIG_VNC_SASL
1361 if (vs->sasl.conn && vs->sasl.runSSF)
1362 ret = vnc_client_read_sasl(vs);
1363 else
1364#endif /* CONFIG_VNC_SASL */
Tim Hardeck7536ee42013-01-21 11:04:44 +01001365#ifdef CONFIG_VNC_WS
1366 if (vs->encode_ws) {
1367 ret = vnc_client_read_ws(vs);
1368 if (ret == -1) {
1369 vnc_disconnect_start(vs);
1370 return;
1371 } else if (ret == -2) {
1372 vnc_client_error(vs);
1373 return;
1374 }
1375 } else
1376#endif /* CONFIG_VNC_WS */
1377 {
aliguori2f9606b2009-03-06 20:27:28 +00001378 ret = vnc_client_read_plain(vs);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001379 }
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001380 if (!ret) {
1381 if (vs->csock == -1)
1382 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001383 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001384 }
bellard24236862006-04-30 21:28:36 +00001385
bellard24236862006-04-30 21:28:36 +00001386 while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
aliguori28a76be2009-03-06 20:27:40 +00001387 size_t len = vs->read_handler_expect;
1388 int ret;
bellard24236862006-04-30 21:28:36 +00001389
aliguori28a76be2009-03-06 20:27:40 +00001390 ret = vs->read_handler(vs, vs->input.buffer, len);
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001391 if (vs->csock == -1) {
1392 vnc_disconnect_finish(vs);
aliguori28a76be2009-03-06 20:27:40 +00001393 return;
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001394 }
bellard24236862006-04-30 21:28:36 +00001395
aliguori28a76be2009-03-06 20:27:40 +00001396 if (!ret) {
Tim Hardeck32ed2682013-01-21 11:04:43 +01001397 buffer_advance(&vs->input, len);
aliguori28a76be2009-03-06 20:27:40 +00001398 } else {
1399 vs->read_handler_expect = ret;
1400 }
bellard24236862006-04-30 21:28:36 +00001401 }
1402}
1403
aliguori5fb6c7a2009-03-06 20:27:23 +00001404void vnc_write(VncState *vs, const void *data, size_t len)
bellard24236862006-04-30 21:28:36 +00001405{
1406 buffer_reserve(&vs->output, len);
1407
Gerd Hoffmann198a0032009-06-16 14:19:48 +02001408 if (vs->csock != -1 && buffer_empty(&vs->output)) {
aliguori28a76be2009-03-06 20:27:40 +00001409 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
bellard24236862006-04-30 21:28:36 +00001410 }
1411
1412 buffer_append(&vs->output, data, len);
1413}
1414
aliguori5fb6c7a2009-03-06 20:27:23 +00001415void vnc_write_s32(VncState *vs, int32_t value)
bellard24236862006-04-30 21:28:36 +00001416{
1417 vnc_write_u32(vs, *(uint32_t *)&value);
1418}
1419
aliguori5fb6c7a2009-03-06 20:27:23 +00001420void vnc_write_u32(VncState *vs, uint32_t value)
bellard24236862006-04-30 21:28:36 +00001421{
1422 uint8_t buf[4];
1423
1424 buf[0] = (value >> 24) & 0xFF;
1425 buf[1] = (value >> 16) & 0xFF;
1426 buf[2] = (value >> 8) & 0xFF;
1427 buf[3] = value & 0xFF;
1428
1429 vnc_write(vs, buf, 4);
1430}
1431
aliguori5fb6c7a2009-03-06 20:27:23 +00001432void vnc_write_u16(VncState *vs, uint16_t value)
bellard24236862006-04-30 21:28:36 +00001433{
bellard64f5a132006-08-24 20:36:44 +00001434 uint8_t buf[2];
bellard24236862006-04-30 21:28:36 +00001435
1436 buf[0] = (value >> 8) & 0xFF;
1437 buf[1] = value & 0xFF;
1438
1439 vnc_write(vs, buf, 2);
1440}
1441
aliguori5fb6c7a2009-03-06 20:27:23 +00001442void vnc_write_u8(VncState *vs, uint8_t value)
bellard24236862006-04-30 21:28:36 +00001443{
1444 vnc_write(vs, (char *)&value, 1);
1445}
1446
aliguori5fb6c7a2009-03-06 20:27:23 +00001447void vnc_flush(VncState *vs)
bellard24236862006-04-30 21:28:36 +00001448{
Corentin Charybd023f92010-07-07 20:58:02 +02001449 vnc_lock_output(vs);
Tim Hardeck7536ee42013-01-21 11:04:44 +01001450 if (vs->csock != -1 && (vs->output.offset
1451#ifdef CONFIG_VNC_WS
1452 || vs->ws_output.offset
1453#endif
1454 )) {
Corentin Charybd023f92010-07-07 20:58:02 +02001455 vnc_client_write_locked(vs);
1456 }
1457 vnc_unlock_output(vs);
bellard24236862006-04-30 21:28:36 +00001458}
1459
Blue Swirl71a8cde2012-10-28 11:04:48 +00001460static uint8_t read_u8(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001461{
1462 return data[offset];
1463}
1464
Blue Swirl71a8cde2012-10-28 11:04:48 +00001465static uint16_t read_u16(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001466{
1467 return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
1468}
1469
Blue Swirl71a8cde2012-10-28 11:04:48 +00001470static int32_t read_s32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001471{
1472 return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001473 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001474}
1475
aliguori5fb6c7a2009-03-06 20:27:23 +00001476uint32_t read_u32(uint8_t *data, size_t offset)
bellard24236862006-04-30 21:28:36 +00001477{
1478 return ((data[offset] << 24) | (data[offset + 1] << 16) |
aliguori28a76be2009-03-06 20:27:40 +00001479 (data[offset + 2] << 8) | data[offset + 3]);
bellard24236862006-04-30 21:28:36 +00001480}
1481
ths60fe76f2007-12-16 03:02:09 +00001482static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
bellard24236862006-04-30 21:28:36 +00001483{
1484}
1485
Jan Kiszka9e8dd452011-06-20 14:06:26 +02001486static void check_pointer_type_change(Notifier *notifier, void *data)
bellard564c3372007-02-05 20:14:10 +00001487{
Anthony Liguori37c34d92010-03-10 09:38:29 -06001488 VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001489 int absolute = qemu_input_is_absolute();
Anthony Liguori37c34d92010-03-10 09:38:29 -06001490
aliguori29fa4ed2009-02-02 15:58:29 +00001491 if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
Corentin Charybd023f92010-07-07 20:58:02 +02001492 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001493 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
aliguori28a76be2009-03-06 20:27:40 +00001494 vnc_write_u8(vs, 0);
1495 vnc_write_u16(vs, 1);
1496 vnc_framebuffer_update(vs, absolute, 0,
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01001497 surface_width(vs->vd->ds),
1498 surface_height(vs->vd->ds),
aliguori29fa4ed2009-02-02 15:58:29 +00001499 VNC_ENCODING_POINTER_TYPE_CHANGE);
Corentin Charybd023f92010-07-07 20:58:02 +02001500 vnc_unlock_output(vs);
aliguori28a76be2009-03-06 20:27:40 +00001501 vnc_flush(vs);
bellard564c3372007-02-05 20:14:10 +00001502 }
1503 vs->absolute = absolute;
1504}
1505
bellard24236862006-04-30 21:28:36 +00001506static void pointer_event(VncState *vs, int button_mask, int x, int y)
1507{
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001508 static uint32_t bmap[INPUT_BUTTON_MAX] = {
1509 [INPUT_BUTTON_LEFT] = 0x01,
1510 [INPUT_BUTTON_MIDDLE] = 0x02,
1511 [INPUT_BUTTON_RIGHT] = 0x04,
1512 [INPUT_BUTTON_WHEEL_UP] = 0x08,
1513 [INPUT_BUTTON_WHEEL_DOWN] = 0x10,
1514 };
1515 QemuConsole *con = vs->vd->dcl.con;
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01001516 int width = surface_width(vs->vd->ds);
1517 int height = surface_height(vs->vd->ds);
bellard24236862006-04-30 21:28:36 +00001518
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001519 if (vs->last_bmask != button_mask) {
1520 qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
1521 vs->last_bmask = button_mask;
1522 }
bellard564c3372007-02-05 20:14:10 +00001523
1524 if (vs->absolute) {
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001525 qemu_input_queue_abs(con, INPUT_AXIS_X, x, width);
1526 qemu_input_queue_abs(con, INPUT_AXIS_Y, y, height);
aliguori29fa4ed2009-02-02 15:58:29 +00001527 } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001528 qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF);
1529 qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF);
bellard24236862006-04-30 21:28:36 +00001530 } else {
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001531 if (vs->last_x != -1) {
1532 qemu_input_queue_rel(con, INPUT_AXIS_X, x - vs->last_x);
1533 qemu_input_queue_rel(con, INPUT_AXIS_Y, y - vs->last_y);
1534 }
aliguori28a76be2009-03-06 20:27:40 +00001535 vs->last_x = x;
1536 vs->last_y = y;
bellard24236862006-04-30 21:28:36 +00001537 }
Gerd Hoffmann14768eb2013-12-02 15:17:45 +01001538 qemu_input_event_sync();
bellard24236862006-04-30 21:28:36 +00001539}
1540
bellard64f5a132006-08-24 20:36:44 +00001541static void reset_keys(VncState *vs)
1542{
1543 int i;
1544 for(i = 0; i < 256; i++) {
1545 if (vs->modifiers_state[i]) {
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001546 qemu_input_event_send_key_number(vs->vd->dcl.con, i, false);
bellard64f5a132006-08-24 20:36:44 +00001547 vs->modifiers_state[i] = 0;
1548 }
1549 }
1550}
1551
balroga528b802007-10-30 22:38:53 +00001552static void press_key(VncState *vs, int keysym)
1553{
Samuel Thibault44bb61c2010-02-28 21:03:00 +01001554 int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001555 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
Gerd Hoffmann2deb4ac2014-06-02 13:15:05 +02001556 qemu_input_event_send_key_delay(0);
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001557 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
Gerd Hoffmann2deb4ac2014-06-02 13:15:05 +02001558 qemu_input_event_send_key_delay(0);
balroga528b802007-10-30 22:38:53 +00001559}
1560
Lei Liab99e5c2013-04-25 13:29:10 +08001561static int current_led_state(VncState *vs)
1562{
1563 int ledstate = 0;
1564
1565 if (vs->modifiers_state[0x46]) {
1566 ledstate |= QEMU_SCROLL_LOCK_LED;
1567 }
1568 if (vs->modifiers_state[0x45]) {
1569 ledstate |= QEMU_NUM_LOCK_LED;
1570 }
1571 if (vs->modifiers_state[0x3a]) {
1572 ledstate |= QEMU_CAPS_LOCK_LED;
1573 }
1574
1575 return ledstate;
1576}
1577
1578static void vnc_led_state_change(VncState *vs)
1579{
1580 int ledstate = 0;
1581
1582 if (!vnc_has_feature(vs, VNC_FEATURE_LED_STATE)) {
1583 return;
1584 }
1585
1586 ledstate = current_led_state(vs);
1587 vnc_lock_output(vs);
1588 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1589 vnc_write_u8(vs, 0);
1590 vnc_write_u16(vs, 1);
1591 vnc_framebuffer_update(vs, 0, 0, 1, 1, VNC_ENCODING_LED_STATE);
1592 vnc_write_u8(vs, ledstate);
1593 vnc_unlock_output(vs);
1594 vnc_flush(vs);
1595}
1596
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001597static void kbd_leds(void *opaque, int ledstate)
1598{
1599 VncState *vs = opaque;
Lei Li96f3d172013-04-25 13:29:09 +08001600 int caps, num, scr;
Lei Li1483adc2013-05-15 16:20:40 +08001601 bool has_changed = (ledstate != current_led_state(vs));
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001602
Gerd Hoffmann40066172014-05-21 13:18:20 +02001603 trace_vnc_key_guest_leds((ledstate & QEMU_CAPS_LOCK_LED),
1604 (ledstate & QEMU_NUM_LOCK_LED),
1605 (ledstate & QEMU_SCROLL_LOCK_LED));
1606
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001607 caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
1608 num = ledstate & QEMU_NUM_LOCK_LED ? 1 : 0;
Lei Li96f3d172013-04-25 13:29:09 +08001609 scr = ledstate & QEMU_SCROLL_LOCK_LED ? 1 : 0;
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001610
1611 if (vs->modifiers_state[0x3a] != caps) {
1612 vs->modifiers_state[0x3a] = caps;
1613 }
1614 if (vs->modifiers_state[0x45] != num) {
1615 vs->modifiers_state[0x45] = num;
1616 }
Lei Li96f3d172013-04-25 13:29:09 +08001617 if (vs->modifiers_state[0x46] != scr) {
1618 vs->modifiers_state[0x46] = scr;
1619 }
Lei Liab99e5c2013-04-25 13:29:10 +08001620
1621 /* Sending the current led state message to the client */
Lei Li1483adc2013-05-15 16:20:40 +08001622 if (has_changed) {
Lei Liab99e5c2013-04-25 13:29:10 +08001623 vnc_led_state_change(vs);
1624 }
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001625}
1626
aliguori9ca313a2008-08-23 23:27:37 +00001627static void do_key_event(VncState *vs, int down, int keycode, int sym)
bellard24236862006-04-30 21:28:36 +00001628{
bellard64f5a132006-08-24 20:36:44 +00001629 /* QEMU console switch */
1630 switch(keycode) {
1631 case 0x2a: /* Left Shift */
1632 case 0x36: /* Right Shift */
1633 case 0x1d: /* Left CTRL */
1634 case 0x9d: /* Right CTRL */
1635 case 0x38: /* Left ALT */
1636 case 0xb8: /* Right ALT */
1637 if (down)
1638 vs->modifiers_state[keycode] = 1;
1639 else
1640 vs->modifiers_state[keycode] = 0;
1641 break;
ths5fafdf22007-09-16 21:08:06 +00001642 case 0x02 ... 0x0a: /* '1' to '9' keys */
bellard64f5a132006-08-24 20:36:44 +00001643 if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1644 /* Reset the modifiers sent to the current console */
1645 reset_keys(vs);
1646 console_select(keycode - 0x02);
1647 return;
1648 }
1649 break;
aliguori28a76be2009-03-06 20:27:40 +00001650 case 0x3a: /* CapsLock */
1651 case 0x45: /* NumLock */
Gerd Hoffmann7ffb82c2010-02-26 17:17:39 +01001652 if (down)
balroga528b802007-10-30 22:38:53 +00001653 vs->modifiers_state[keycode] ^= 1;
1654 break;
1655 }
1656
Lei Lie7b2aac2013-04-25 13:29:11 +08001657 /* Turn off the lock state sync logic if the client support the led
1658 state extension.
1659 */
Gerd Hoffmann98920882011-01-14 10:56:54 +01001660 if (down && vs->vd->lock_key_sync &&
Lei Lie7b2aac2013-04-25 13:29:11 +08001661 !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01001662 keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
balroga528b802007-10-30 22:38:53 +00001663 /* If the numlock state needs to change then simulate an additional
1664 keypress before sending this one. This will happen if the user
1665 toggles numlock away from the VNC window.
1666 */
aliguori753b4052009-02-16 14:59:30 +00001667 if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
balroga528b802007-10-30 22:38:53 +00001668 if (!vs->modifiers_state[0x45]) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001669 trace_vnc_key_sync_numlock(true);
balroga528b802007-10-30 22:38:53 +00001670 vs->modifiers_state[0x45] = 1;
1671 press_key(vs, 0xff7f);
1672 }
1673 } else {
1674 if (vs->modifiers_state[0x45]) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001675 trace_vnc_key_sync_numlock(false);
balroga528b802007-10-30 22:38:53 +00001676 vs->modifiers_state[0x45] = 0;
1677 press_key(vs, 0xff7f);
1678 }
1679 }
bellard64f5a132006-08-24 20:36:44 +00001680 }
bellard24236862006-04-30 21:28:36 +00001681
Gerd Hoffmann98920882011-01-14 10:56:54 +01001682 if (down && vs->vd->lock_key_sync &&
Lei Lie7b2aac2013-04-25 13:29:11 +08001683 !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01001684 ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001685 /* If the capslock state needs to change then simulate an additional
1686 keypress before sending this one. This will happen if the user
1687 toggles capslock away from the VNC window.
1688 */
1689 int uppercase = !!(sym >= 'A' && sym <= 'Z');
1690 int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
1691 int capslock = !!(vs->modifiers_state[0x3a]);
1692 if (capslock) {
1693 if (uppercase == shift) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001694 trace_vnc_key_sync_capslock(false);
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001695 vs->modifiers_state[0x3a] = 0;
1696 press_key(vs, 0xffe5);
1697 }
1698 } else {
1699 if (uppercase != shift) {
Gerd Hoffmann40066172014-05-21 13:18:20 +02001700 trace_vnc_key_sync_capslock(true);
Gerd Hoffmann6b132502009-11-02 12:47:06 +01001701 vs->modifiers_state[0x3a] = 1;
1702 press_key(vs, 0xffe5);
1703 }
1704 }
1705 }
1706
Gerd Hoffmann81c0d5a2013-03-14 14:27:08 +01001707 if (qemu_console_is_graphic(NULL)) {
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001708 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
bellard64f5a132006-08-24 20:36:44 +00001709 } else {
Gerd Hoffmanne26437c2011-11-08 10:02:16 +01001710 bool numlock = vs->modifiers_state[0x45];
1711 bool control = (vs->modifiers_state[0x1d] ||
1712 vs->modifiers_state[0x9d]);
bellard64f5a132006-08-24 20:36:44 +00001713 /* QEMU console emulation */
1714 if (down) {
1715 switch (keycode) {
1716 case 0x2a: /* Left Shift */
1717 case 0x36: /* Right Shift */
1718 case 0x1d: /* Left CTRL */
1719 case 0x9d: /* Right CTRL */
1720 case 0x38: /* Left ALT */
1721 case 0xb8: /* Right ALT */
1722 break;
1723 case 0xc8:
1724 kbd_put_keysym(QEMU_KEY_UP);
1725 break;
1726 case 0xd0:
1727 kbd_put_keysym(QEMU_KEY_DOWN);
1728 break;
1729 case 0xcb:
1730 kbd_put_keysym(QEMU_KEY_LEFT);
1731 break;
1732 case 0xcd:
1733 kbd_put_keysym(QEMU_KEY_RIGHT);
1734 break;
1735 case 0xd3:
1736 kbd_put_keysym(QEMU_KEY_DELETE);
1737 break;
1738 case 0xc7:
1739 kbd_put_keysym(QEMU_KEY_HOME);
1740 break;
1741 case 0xcf:
1742 kbd_put_keysym(QEMU_KEY_END);
1743 break;
1744 case 0xc9:
1745 kbd_put_keysym(QEMU_KEY_PAGEUP);
1746 break;
1747 case 0xd1:
1748 kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1749 break;
Gerd Hoffmannbb0a18e2009-06-11 11:32:14 +02001750
1751 case 0x47:
1752 kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
1753 break;
1754 case 0x48:
1755 kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
1756 break;
1757 case 0x49:
1758 kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
1759 break;
1760 case 0x4b:
1761 kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
1762 break;
1763 case 0x4c:
1764 kbd_put_keysym('5');
1765 break;
1766 case 0x4d:
1767 kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
1768 break;
1769 case 0x4f:
1770 kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
1771 break;
1772 case 0x50:
1773 kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
1774 break;
1775 case 0x51:
1776 kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
1777 break;
1778 case 0x52:
1779 kbd_put_keysym('0');
1780 break;
1781 case 0x53:
1782 kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
1783 break;
1784
1785 case 0xb5:
1786 kbd_put_keysym('/');
1787 break;
1788 case 0x37:
1789 kbd_put_keysym('*');
1790 break;
1791 case 0x4a:
1792 kbd_put_keysym('-');
1793 break;
1794 case 0x4e:
1795 kbd_put_keysym('+');
1796 break;
1797 case 0x9c:
1798 kbd_put_keysym('\n');
1799 break;
1800
bellard64f5a132006-08-24 20:36:44 +00001801 default:
Gerd Hoffmanne26437c2011-11-08 10:02:16 +01001802 if (control) {
1803 kbd_put_keysym(sym & 0x1f);
1804 } else {
1805 kbd_put_keysym(sym);
1806 }
bellard64f5a132006-08-24 20:36:44 +00001807 break;
1808 }
1809 }
1810 }
bellard24236862006-04-30 21:28:36 +00001811}
1812
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001813static void vnc_release_modifiers(VncState *vs)
1814{
1815 static const int keycodes[] = {
1816 /* shift, control, alt keys, both left & right */
1817 0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8,
1818 };
1819 int i, keycode;
1820
Gerd Hoffmann81c0d5a2013-03-14 14:27:08 +01001821 if (!qemu_console_is_graphic(NULL)) {
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001822 return;
1823 }
1824 for (i = 0; i < ARRAY_SIZE(keycodes); i++) {
1825 keycode = keycodes[i];
1826 if (!vs->modifiers_state[keycode]) {
1827 continue;
1828 }
Gerd Hoffmann8d447d12013-12-02 14:27:18 +01001829 qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
Gerd Hoffmann7bc93182012-02-08 13:18:37 +01001830 }
1831}
1832
Gerd Hoffmann40066172014-05-21 13:18:20 +02001833static const char *code2name(int keycode)
1834{
1835 return QKeyCode_lookup[qemu_input_key_number_to_qcode(keycode)];
1836}
1837
bellardbdbd7672006-05-01 21:44:22 +00001838static void key_event(VncState *vs, int down, uint32_t sym)
1839{
aliguori9ca313a2008-08-23 23:27:37 +00001840 int keycode;
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001841 int lsym = sym;
aliguori9ca313a2008-08-23 23:27:37 +00001842
Gerd Hoffmann81c0d5a2013-03-14 14:27:08 +01001843 if (lsym >= 'A' && lsym <= 'Z' && qemu_console_is_graphic(NULL)) {
Gerd Hoffmann4a93fe12009-12-11 11:25:07 +01001844 lsym = lsym - 'A' + 'a';
1845 }
aliguori9ca313a2008-08-23 23:27:37 +00001846
Samuel Thibault44bb61c2010-02-28 21:03:00 +01001847 keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
Gerd Hoffmann40066172014-05-21 13:18:20 +02001848 trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
aliguori9ca313a2008-08-23 23:27:37 +00001849 do_key_event(vs, down, keycode, sym);
1850}
1851
1852static void ext_key_event(VncState *vs, int down,
1853 uint32_t sym, uint16_t keycode)
1854{
1855 /* if the user specifies a keyboard layout, always use it */
Gerd Hoffmann40066172014-05-21 13:18:20 +02001856 if (keyboard_layout) {
aliguori9ca313a2008-08-23 23:27:37 +00001857 key_event(vs, down, sym);
Gerd Hoffmann40066172014-05-21 13:18:20 +02001858 } else {
1859 trace_vnc_key_event_ext(down, sym, keycode, code2name(keycode));
aliguori9ca313a2008-08-23 23:27:37 +00001860 do_key_event(vs, down, keycode, sym);
Gerd Hoffmann40066172014-05-21 13:18:20 +02001861 }
bellardbdbd7672006-05-01 21:44:22 +00001862}
1863
bellard24236862006-04-30 21:28:36 +00001864static void framebuffer_update_request(VncState *vs, int incremental,
aliguori28a76be2009-03-06 20:27:40 +00001865 int x_position, int y_position,
1866 int w, int h)
bellard24236862006-04-30 21:28:36 +00001867{
Wen Congyang6ed391b2011-03-11 17:10:32 +08001868 int i;
Peter Lievenb4c85dd2014-01-08 10:08:33 +01001869 const size_t width = surface_width(vs->vd->ds) / VNC_DIRTY_PIXELS_PER_BIT;
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01001870 const size_t height = surface_height(vs->vd->ds);
Wen Congyang6ed391b2011-03-11 17:10:32 +08001871
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01001872 if (y_position > height) {
1873 y_position = height;
1874 }
1875 if (y_position + h >= height) {
1876 h = height - y_position;
1877 }
thscf2d3852007-04-29 01:53:20 +00001878
bellard24236862006-04-30 21:28:36 +00001879 vs->need_update = 1;
1880 if (!incremental) {
Gerd Hoffmann24cf0a62009-04-27 16:39:52 +02001881 vs->force_update = 1;
aliguori28a76be2009-03-06 20:27:40 +00001882 for (i = 0; i < h; i++) {
Wen Congyang6ed391b2011-03-11 17:10:32 +08001883 bitmap_set(vs->dirty[y_position + i], 0, width);
1884 bitmap_clear(vs->dirty[y_position + i], width,
Anthony Liguoria0843a62011-03-22 11:27:33 -05001885 VNC_DIRTY_BITS - width);
aliguori28a76be2009-03-06 20:27:40 +00001886 }
bellard24236862006-04-30 21:28:36 +00001887 }
1888}
1889
aliguori9ca313a2008-08-23 23:27:37 +00001890static void send_ext_key_event_ack(VncState *vs)
1891{
Corentin Charybd023f92010-07-07 20:58:02 +02001892 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001893 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
aliguori9ca313a2008-08-23 23:27:37 +00001894 vnc_write_u8(vs, 0);
1895 vnc_write_u16(vs, 1);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01001896 vnc_framebuffer_update(vs, 0, 0,
1897 surface_width(vs->vd->ds),
1898 surface_height(vs->vd->ds),
aliguori29fa4ed2009-02-02 15:58:29 +00001899 VNC_ENCODING_EXT_KEY_EVENT);
Corentin Charybd023f92010-07-07 20:58:02 +02001900 vnc_unlock_output(vs);
aliguori9ca313a2008-08-23 23:27:37 +00001901 vnc_flush(vs);
1902}
1903
malc429a8ed2008-12-01 20:57:48 +00001904static void send_ext_audio_ack(VncState *vs)
1905{
Corentin Charybd023f92010-07-07 20:58:02 +02001906 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01001907 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
malc429a8ed2008-12-01 20:57:48 +00001908 vnc_write_u8(vs, 0);
1909 vnc_write_u16(vs, 1);
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01001910 vnc_framebuffer_update(vs, 0, 0,
1911 surface_width(vs->vd->ds),
1912 surface_height(vs->vd->ds),
aliguori29fa4ed2009-02-02 15:58:29 +00001913 VNC_ENCODING_AUDIO);
Corentin Charybd023f92010-07-07 20:58:02 +02001914 vnc_unlock_output(vs);
malc429a8ed2008-12-01 20:57:48 +00001915 vnc_flush(vs);
1916}
1917
bellard24236862006-04-30 21:28:36 +00001918static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1919{
1920 int i;
aliguori29fa4ed2009-02-02 15:58:29 +00001921 unsigned int enc = 0;
bellard24236862006-04-30 21:28:36 +00001922
aliguori29fa4ed2009-02-02 15:58:29 +00001923 vs->features = 0;
Corentin Charya9f20d32010-05-19 09:24:01 +02001924 vs->vnc_encoding = 0;
Corentin Charyd1af0e02010-07-07 20:57:59 +02001925 vs->tight.compression = 9;
1926 vs->tight.quality = -1; /* Lossless by default */
bellard564c3372007-02-05 20:14:10 +00001927 vs->absolute = -1;
bellard24236862006-04-30 21:28:36 +00001928
Corentin Chary8a0f0d02010-05-19 09:24:02 +02001929 /*
1930 * Start from the end because the encodings are sent in order of preference.
Dong Xu Wange5bed752011-11-22 18:06:24 +08001931 * This way the preferred encoding (first encoding defined in the array)
Corentin Chary8a0f0d02010-05-19 09:24:02 +02001932 * will be set at the end of the loop.
1933 */
bellard24236862006-04-30 21:28:36 +00001934 for (i = n_encodings - 1; i >= 0; i--) {
aliguori29fa4ed2009-02-02 15:58:29 +00001935 enc = encodings[i];
1936 switch (enc) {
1937 case VNC_ENCODING_RAW:
Corentin Charya9f20d32010-05-19 09:24:01 +02001938 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001939 break;
1940 case VNC_ENCODING_COPYRECT:
aliguori753b4052009-02-16 14:59:30 +00001941 vs->features |= VNC_FEATURE_COPYRECT_MASK;
aliguori29fa4ed2009-02-02 15:58:29 +00001942 break;
1943 case VNC_ENCODING_HEXTILE:
1944 vs->features |= VNC_FEATURE_HEXTILE_MASK;
Corentin Charya9f20d32010-05-19 09:24:01 +02001945 vs->vnc_encoding = enc;
aliguori29fa4ed2009-02-02 15:58:29 +00001946 break;
Corentin Chary380282b2010-05-19 09:24:10 +02001947 case VNC_ENCODING_TIGHT:
1948 vs->features |= VNC_FEATURE_TIGHT_MASK;
1949 vs->vnc_encoding = enc;
1950 break;
Joel Martinfe3e7f22012-05-16 12:54:25 +00001951#ifdef CONFIG_VNC_PNG
Corentin Charyefe556a2010-07-07 20:57:56 +02001952 case VNC_ENCODING_TIGHT_PNG:
1953 vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
1954 vs->vnc_encoding = enc;
1955 break;
Joel Martinfe3e7f22012-05-16 12:54:25 +00001956#endif
aliguori059cef42009-02-02 15:58:54 +00001957 case VNC_ENCODING_ZLIB:
1958 vs->features |= VNC_FEATURE_ZLIB_MASK;
Corentin Charya9f20d32010-05-19 09:24:01 +02001959 vs->vnc_encoding = enc;
aliguori059cef42009-02-02 15:58:54 +00001960 break;
Corentin Chary148954f2011-02-04 09:06:01 +01001961 case VNC_ENCODING_ZRLE:
1962 vs->features |= VNC_FEATURE_ZRLE_MASK;
1963 vs->vnc_encoding = enc;
1964 break;
1965 case VNC_ENCODING_ZYWRLE:
1966 vs->features |= VNC_FEATURE_ZYWRLE_MASK;
1967 vs->vnc_encoding = enc;
1968 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001969 case VNC_ENCODING_DESKTOPRESIZE:
1970 vs->features |= VNC_FEATURE_RESIZE_MASK;
1971 break;
1972 case VNC_ENCODING_POINTER_TYPE_CHANGE:
1973 vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
1974 break;
Gerd Hoffmannd467b672010-05-21 11:54:34 +02001975 case VNC_ENCODING_RICH_CURSOR:
1976 vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
1977 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001978 case VNC_ENCODING_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00001979 send_ext_key_event_ack(vs);
1980 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001981 case VNC_ENCODING_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00001982 send_ext_audio_ack(vs);
1983 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001984 case VNC_ENCODING_WMVi:
1985 vs->features |= VNC_FEATURE_WMVI_MASK;
aliguorica4cca42008-09-15 16:05:16 +00001986 break;
Lei Liab99e5c2013-04-25 13:29:10 +08001987 case VNC_ENCODING_LED_STATE:
1988 vs->features |= VNC_FEATURE_LED_STATE_MASK;
1989 break;
aliguorifb437312009-02-02 15:58:43 +00001990 case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
Corentin Charyd1af0e02010-07-07 20:57:59 +02001991 vs->tight.compression = (enc & 0x0F);
aliguorifb437312009-02-02 15:58:43 +00001992 break;
1993 case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
Corentin Charyb31f5192011-02-04 09:05:54 +01001994 if (vs->vd->lossy) {
1995 vs->tight.quality = (enc & 0x0F);
1996 }
aliguorifb437312009-02-02 15:58:43 +00001997 break;
aliguori29fa4ed2009-02-02 15:58:29 +00001998 default:
1999 VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
2000 break;
2001 }
bellard24236862006-04-30 21:28:36 +00002002 }
Gerd Hoffmann6356e472010-05-25 18:25:17 +02002003 vnc_desktop_resize(vs);
Jan Kiszka9e8dd452011-06-20 14:06:26 +02002004 check_pointer_type_change(&vs->mouse_mode_notifier, NULL);
Lei Liab99e5c2013-04-25 13:29:10 +08002005 vnc_led_state_change(vs);
bellard24236862006-04-30 21:28:36 +00002006}
2007
aliguori6cec5482009-01-15 22:17:38 +00002008static void set_pixel_conversion(VncState *vs)
2009{
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002010 pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf);
2011
2012 if (fmt == VNC_SERVER_FB_FORMAT) {
aliguori6cec5482009-01-15 22:17:38 +00002013 vs->write_pixels = vnc_write_pixels_copy;
Corentin Chary70a45682010-05-03 14:31:34 +02002014 vnc_hextile_set_pixel_conversion(vs, 0);
aliguori6cec5482009-01-15 22:17:38 +00002015 } else {
2016 vs->write_pixels = vnc_write_pixels_generic;
Corentin Chary70a45682010-05-03 14:31:34 +02002017 vnc_hextile_set_pixel_conversion(vs, 1);
aliguori6cec5482009-01-15 22:17:38 +00002018 }
2019}
2020
bellard24236862006-04-30 21:28:36 +00002021static void set_pixel_format(VncState *vs,
aliguori28a76be2009-03-06 20:27:40 +00002022 int bits_per_pixel, int depth,
2023 int big_endian_flag, int true_color_flag,
2024 int red_max, int green_max, int blue_max,
2025 int red_shift, int green_shift, int blue_shift)
bellard24236862006-04-30 21:28:36 +00002026{
bellard35127792006-05-14 18:11:49 +00002027 if (!true_color_flag) {
aliguori28a76be2009-03-06 20:27:40 +00002028 vnc_client_error(vs);
bellard35127792006-05-14 18:11:49 +00002029 return;
2030 }
aliguori7eac3a82008-09-15 16:03:41 +00002031
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002032 vs->client_pf.rmax = red_max;
2033 vs->client_pf.rbits = hweight_long(red_max);
2034 vs->client_pf.rshift = red_shift;
2035 vs->client_pf.rmask = red_max << red_shift;
2036 vs->client_pf.gmax = green_max;
2037 vs->client_pf.gbits = hweight_long(green_max);
2038 vs->client_pf.gshift = green_shift;
2039 vs->client_pf.gmask = green_max << green_shift;
2040 vs->client_pf.bmax = blue_max;
2041 vs->client_pf.bbits = hweight_long(blue_max);
2042 vs->client_pf.bshift = blue_shift;
2043 vs->client_pf.bmask = blue_max << blue_shift;
2044 vs->client_pf.bits_per_pixel = bits_per_pixel;
2045 vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
2046 vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
2047 vs->client_be = big_endian_flag;
bellard24236862006-04-30 21:28:36 +00002048
aliguori6cec5482009-01-15 22:17:38 +00002049 set_pixel_conversion(vs);
bellard24236862006-04-30 21:28:36 +00002050
Gerd Hoffmann1dbfa002013-03-12 13:44:38 +01002051 graphic_hw_invalidate(NULL);
2052 graphic_hw_update(NULL);
bellard24236862006-04-30 21:28:36 +00002053}
2054
aliguorica4cca42008-09-15 16:05:16 +00002055static void pixel_format_message (VncState *vs) {
2056 char pad[3] = { 0, 0, 0 };
2057
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002058 vs->client_pf = qemu_default_pixelformat(32);
2059
2060 vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */
2061 vnc_write_u8(vs, vs->client_pf.depth); /* depth */
aliguorica4cca42008-09-15 16:05:16 +00002062
Juan Quintelae2542fe2009-07-27 16:13:06 +02002063#ifdef HOST_WORDS_BIGENDIAN
aliguorica4cca42008-09-15 16:05:16 +00002064 vnc_write_u8(vs, 1); /* big-endian-flag */
2065#else
2066 vnc_write_u8(vs, 0); /* big-endian-flag */
2067#endif
2068 vnc_write_u8(vs, 1); /* true-color-flag */
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002069 vnc_write_u16(vs, vs->client_pf.rmax); /* red-max */
2070 vnc_write_u16(vs, vs->client_pf.gmax); /* green-max */
2071 vnc_write_u16(vs, vs->client_pf.bmax); /* blue-max */
2072 vnc_write_u8(vs, vs->client_pf.rshift); /* red-shift */
2073 vnc_write_u8(vs, vs->client_pf.gshift); /* green-shift */
2074 vnc_write_u8(vs, vs->client_pf.bshift); /* blue-shift */
2075 vnc_write(vs, pad, 3); /* padding */
Corentin Chary70a45682010-05-03 14:31:34 +02002076
2077 vnc_hextile_set_pixel_conversion(vs, 0);
aliguorica4cca42008-09-15 16:05:16 +00002078 vs->write_pixels = vnc_write_pixels_copy;
aliguorica4cca42008-09-15 16:05:16 +00002079}
2080
aliguori753b4052009-02-16 14:59:30 +00002081static void vnc_colordepth(VncState *vs)
aliguori7eac3a82008-09-15 16:03:41 +00002082{
aliguori753b4052009-02-16 14:59:30 +00002083 if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
aliguorica4cca42008-09-15 16:05:16 +00002084 /* Sending a WMVi message to notify the client*/
Corentin Charybd023f92010-07-07 20:58:02 +02002085 vnc_lock_output(vs);
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002086 vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
aliguorica4cca42008-09-15 16:05:16 +00002087 vnc_write_u8(vs, 0);
2088 vnc_write_u16(vs, 1); /* number of rects */
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01002089 vnc_framebuffer_update(vs, 0, 0,
2090 surface_width(vs->vd->ds),
2091 surface_height(vs->vd->ds),
2092 VNC_ENCODING_WMVi);
aliguorica4cca42008-09-15 16:05:16 +00002093 pixel_format_message(vs);
Corentin Charybd023f92010-07-07 20:58:02 +02002094 vnc_unlock_output(vs);
aliguorica4cca42008-09-15 16:05:16 +00002095 vnc_flush(vs);
aliguori7eac3a82008-09-15 16:03:41 +00002096 } else {
aliguori6cec5482009-01-15 22:17:38 +00002097 set_pixel_conversion(vs);
aliguori7eac3a82008-09-15 16:03:41 +00002098 }
2099}
2100
ths60fe76f2007-12-16 03:02:09 +00002101static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00002102{
2103 int i;
2104 uint16_t limit;
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002105 VncDisplay *vd = vs->vd;
2106
2107 if (data[0] > 3) {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002108 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002109 }
bellard24236862006-04-30 21:28:36 +00002110
2111 switch (data[0]) {
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002112 case VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
aliguori28a76be2009-03-06 20:27:40 +00002113 if (len == 1)
2114 return 20;
bellard24236862006-04-30 21:28:36 +00002115
aliguori28a76be2009-03-06 20:27:40 +00002116 set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
2117 read_u8(data, 6), read_u8(data, 7),
2118 read_u16(data, 8), read_u16(data, 10),
2119 read_u16(data, 12), read_u8(data, 14),
2120 read_u8(data, 15), read_u8(data, 16));
2121 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002122 case VNC_MSG_CLIENT_SET_ENCODINGS:
aliguori28a76be2009-03-06 20:27:40 +00002123 if (len == 1)
2124 return 4;
bellard24236862006-04-30 21:28:36 +00002125
aliguori28a76be2009-03-06 20:27:40 +00002126 if (len == 4) {
aliguori69dd5c92008-12-22 21:06:23 +00002127 limit = read_u16(data, 2);
2128 if (limit > 0)
2129 return 4 + (limit * 4);
2130 } else
2131 limit = read_u16(data, 2);
bellard24236862006-04-30 21:28:36 +00002132
aliguori28a76be2009-03-06 20:27:40 +00002133 for (i = 0; i < limit; i++) {
2134 int32_t val = read_s32(data, 4 + (i * 4));
2135 memcpy(data + 4 + (i * 4), &val, sizeof(val));
2136 }
bellard24236862006-04-30 21:28:36 +00002137
aliguori28a76be2009-03-06 20:27:40 +00002138 set_encodings(vs, (int32_t *)(data + 4), limit);
2139 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002140 case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
aliguori28a76be2009-03-06 20:27:40 +00002141 if (len == 1)
2142 return 10;
bellard24236862006-04-30 21:28:36 +00002143
aliguori28a76be2009-03-06 20:27:40 +00002144 framebuffer_update_request(vs,
2145 read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
2146 read_u16(data, 6), read_u16(data, 8));
2147 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002148 case VNC_MSG_CLIENT_KEY_EVENT:
aliguori28a76be2009-03-06 20:27:40 +00002149 if (len == 1)
2150 return 8;
bellard24236862006-04-30 21:28:36 +00002151
aliguori28a76be2009-03-06 20:27:40 +00002152 key_event(vs, read_u8(data, 1), read_u32(data, 4));
2153 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002154 case VNC_MSG_CLIENT_POINTER_EVENT:
aliguori28a76be2009-03-06 20:27:40 +00002155 if (len == 1)
2156 return 6;
bellard24236862006-04-30 21:28:36 +00002157
aliguori28a76be2009-03-06 20:27:40 +00002158 pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
2159 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002160 case VNC_MSG_CLIENT_CUT_TEXT:
aliguori28a76be2009-03-06 20:27:40 +00002161 if (len == 1)
2162 return 8;
bellard24236862006-04-30 21:28:36 +00002163
aliguori28a76be2009-03-06 20:27:40 +00002164 if (len == 8) {
thsbaa76662007-09-13 12:41:42 +00002165 uint32_t dlen = read_u32(data, 4);
2166 if (dlen > 0)
2167 return 8 + dlen;
2168 }
bellard24236862006-04-30 21:28:36 +00002169
aliguori28a76be2009-03-06 20:27:40 +00002170 client_cut_text(vs, read_u32(data, 4), data + 8);
2171 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002172 case VNC_MSG_CLIENT_QEMU:
aliguori9ca313a2008-08-23 23:27:37 +00002173 if (len == 1)
2174 return 2;
2175
2176 switch (read_u8(data, 1)) {
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002177 case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
aliguori9ca313a2008-08-23 23:27:37 +00002178 if (len == 2)
2179 return 12;
2180
2181 ext_key_event(vs, read_u16(data, 2),
2182 read_u32(data, 4), read_u32(data, 8));
2183 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002184 case VNC_MSG_CLIENT_QEMU_AUDIO:
malc429a8ed2008-12-01 20:57:48 +00002185 if (len == 2)
2186 return 4;
2187
2188 switch (read_u16 (data, 2)) {
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002189 case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
malc429a8ed2008-12-01 20:57:48 +00002190 audio_add(vs);
2191 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002192 case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
malc429a8ed2008-12-01 20:57:48 +00002193 audio_del(vs);
2194 break;
Daniel P. Berrange46a183d2010-03-31 18:20:43 +01002195 case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
malc429a8ed2008-12-01 20:57:48 +00002196 if (len == 4)
2197 return 10;
2198 switch (read_u8(data, 4)) {
2199 case 0: vs->as.fmt = AUD_FMT_U8; break;
2200 case 1: vs->as.fmt = AUD_FMT_S8; break;
2201 case 2: vs->as.fmt = AUD_FMT_U16; break;
2202 case 3: vs->as.fmt = AUD_FMT_S16; break;
2203 case 4: vs->as.fmt = AUD_FMT_U32; break;
2204 case 5: vs->as.fmt = AUD_FMT_S32; break;
2205 default:
2206 printf("Invalid audio format %d\n", read_u8(data, 4));
2207 vnc_client_error(vs);
2208 break;
2209 }
2210 vs->as.nchannels = read_u8(data, 5);
2211 if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
2212 printf("Invalid audio channel coount %d\n",
2213 read_u8(data, 5));
2214 vnc_client_error(vs);
2215 break;
2216 }
2217 vs->as.freq = read_u32(data, 6);
2218 break;
2219 default:
2220 printf ("Invalid audio message %d\n", read_u8(data, 4));
2221 vnc_client_error(vs);
2222 break;
2223 }
2224 break;
2225
aliguori9ca313a2008-08-23 23:27:37 +00002226 default:
2227 printf("Msg: %d\n", read_u16(data, 0));
2228 vnc_client_error(vs);
2229 break;
2230 }
2231 break;
bellard24236862006-04-30 21:28:36 +00002232 default:
aliguori28a76be2009-03-06 20:27:40 +00002233 printf("Msg: %d\n", data[0]);
2234 vnc_client_error(vs);
2235 break;
bellard24236862006-04-30 21:28:36 +00002236 }
ths5fafdf22007-09-16 21:08:06 +00002237
bellard24236862006-04-30 21:28:36 +00002238 vnc_read_when(vs, protocol_client_msg, 1);
2239 return 0;
2240}
2241
ths60fe76f2007-12-16 03:02:09 +00002242static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
bellard24236862006-04-30 21:28:36 +00002243{
thsc35734b2007-03-19 15:17:08 +00002244 char buf[1024];
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01002245 VncShareMode mode;
thsc35734b2007-03-19 15:17:08 +00002246 int size;
bellard24236862006-04-30 21:28:36 +00002247
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01002248 mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE;
2249 switch (vs->vd->share_policy) {
2250 case VNC_SHARE_POLICY_IGNORE:
2251 /*
2252 * Ignore the shared flag. Nothing to do here.
2253 *
2254 * Doesn't conform to the rfb spec but is traditional qemu
2255 * behavior, thus left here as option for compatibility
2256 * reasons.
2257 */
2258 break;
2259 case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE:
2260 /*
2261 * Policy: Allow clients ask for exclusive access.
2262 *
2263 * Implementation: When a client asks for exclusive access,
2264 * disconnect all others. Shared connects are allowed as long
2265 * as no exclusive connection exists.
2266 *
2267 * This is how the rfb spec suggests to handle the shared flag.
2268 */
2269 if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
2270 VncState *client;
2271 QTAILQ_FOREACH(client, &vs->vd->clients, next) {
2272 if (vs == client) {
2273 continue;
2274 }
2275 if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE &&
2276 client->share_mode != VNC_SHARE_MODE_SHARED) {
2277 continue;
2278 }
2279 vnc_disconnect_start(client);
2280 }
2281 }
2282 if (mode == VNC_SHARE_MODE_SHARED) {
2283 if (vs->vd->num_exclusive > 0) {
2284 vnc_disconnect_start(vs);
2285 return 0;
2286 }
2287 }
2288 break;
2289 case VNC_SHARE_POLICY_FORCE_SHARED:
2290 /*
2291 * Policy: Shared connects only.
2292 * Implementation: Disallow clients asking for exclusive access.
2293 *
2294 * Useful for shared desktop sessions where you don't want
2295 * someone forgetting to say -shared when running the vnc
2296 * client disconnect everybody else.
2297 */
2298 if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
2299 vnc_disconnect_start(vs);
2300 return 0;
2301 }
2302 break;
2303 }
2304 vnc_set_share_mode(vs, mode);
2305
Gerd Hoffmannd39fa6d2013-02-28 17:16:48 +01002306 vs->client_width = surface_width(vs->vd->ds);
2307 vs->client_height = surface_height(vs->vd->ds);
Gerd Hoffmann5862d192010-05-25 18:25:18 +02002308 vnc_write_u16(vs, vs->client_width);
2309 vnc_write_u16(vs, vs->client_height);
bellard24236862006-04-30 21:28:36 +00002310
aliguorica4cca42008-09-15 16:05:16 +00002311 pixel_format_message(vs);
bellard24236862006-04-30 21:28:36 +00002312
thsc35734b2007-03-19 15:17:08 +00002313 if (qemu_name)
2314 size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
2315 else
2316 size = snprintf(buf, sizeof(buf), "QEMU");
2317
2318 vnc_write_u32(vs, size);
2319 vnc_write(vs, buf, size);
bellard24236862006-04-30 21:28:36 +00002320 vnc_flush(vs);
2321
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002322 vnc_client_cache_auth(vs);
Luiz Capitulino0d2ed462010-01-14 14:50:59 -02002323 vnc_qmp_event(vs, QEVENT_VNC_INITIALIZED);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002324
bellard24236862006-04-30 21:28:36 +00002325 vnc_read_when(vs, protocol_client_msg, 1);
2326
2327 return 0;
2328}
2329
aliguori5fb6c7a2009-03-06 20:27:23 +00002330void start_client_init(VncState *vs)
2331{
2332 vnc_read_when(vs, protocol_client_init, 1);
2333}
2334
ths70848512007-08-25 01:37:05 +00002335static void make_challenge(VncState *vs)
bellard24236862006-04-30 21:28:36 +00002336{
ths70848512007-08-25 01:37:05 +00002337 int i;
bellard24236862006-04-30 21:28:36 +00002338
ths70848512007-08-25 01:37:05 +00002339 srand(time(NULL)+getpid()+getpid()*987654+rand());
bellard24236862006-04-30 21:28:36 +00002340
ths70848512007-08-25 01:37:05 +00002341 for (i = 0 ; i < sizeof(vs->challenge) ; i++)
2342 vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
2343}
2344
ths60fe76f2007-12-16 03:02:09 +00002345static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002346{
ths60fe76f2007-12-16 03:02:09 +00002347 unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
ths70848512007-08-25 01:37:05 +00002348 int i, j, pwlen;
ths60fe76f2007-12-16 03:02:09 +00002349 unsigned char key[8];
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02002350 time_t now = time(NULL);
ths70848512007-08-25 01:37:05 +00002351
Anthony Liguori1cd20f82011-01-31 14:27:36 -06002352 if (!vs->vd->password) {
aliguori28a76be2009-03-06 20:27:40 +00002353 VNC_DEBUG("No password configured on server");
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002354 goto reject;
bellard24236862006-04-30 21:28:36 +00002355 }
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02002356 if (vs->vd->expires < now) {
2357 VNC_DEBUG("Password is expired");
2358 goto reject;
2359 }
bellard24236862006-04-30 21:28:36 +00002360
ths70848512007-08-25 01:37:05 +00002361 memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
2362
2363 /* Calculate the expected challenge response */
aliguori753b4052009-02-16 14:59:30 +00002364 pwlen = strlen(vs->vd->password);
ths70848512007-08-25 01:37:05 +00002365 for (i=0; i<sizeof(key); i++)
aliguori753b4052009-02-16 14:59:30 +00002366 key[i] = i<pwlen ? vs->vd->password[i] : 0;
ths70848512007-08-25 01:37:05 +00002367 deskey(key, EN0);
2368 for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
2369 des(response+j, response+j);
2370
2371 /* Compare expected vs actual challenge response */
2372 if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
Dong Xu Wange5bed752011-11-22 18:06:24 +08002373 VNC_DEBUG("Client challenge response did not match\n");
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002374 goto reject;
ths70848512007-08-25 01:37:05 +00002375 } else {
aliguori28a76be2009-03-06 20:27:40 +00002376 VNC_DEBUG("Accepting VNC challenge response\n");
2377 vnc_write_u32(vs, 0); /* Accept auth */
2378 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002379
aliguori5fb6c7a2009-03-06 20:27:23 +00002380 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00002381 }
2382 return 0;
Gerd Hoffmann6bffdf02010-10-07 11:50:24 +02002383
2384reject:
2385 vnc_write_u32(vs, 1); /* Reject auth */
2386 if (vs->minor >= 8) {
2387 static const char err[] = "Authentication failed";
2388 vnc_write_u32(vs, sizeof(err));
2389 vnc_write(vs, err, sizeof(err));
2390 }
2391 vnc_flush(vs);
2392 vnc_client_error(vs);
2393 return 0;
ths70848512007-08-25 01:37:05 +00002394}
2395
aliguori5fb6c7a2009-03-06 20:27:23 +00002396void start_auth_vnc(VncState *vs)
ths70848512007-08-25 01:37:05 +00002397{
2398 make_challenge(vs);
2399 /* Send client a 'random' challenge */
2400 vnc_write(vs, vs->challenge, sizeof(vs->challenge));
bellard24236862006-04-30 21:28:36 +00002401 vnc_flush(vs);
2402
ths70848512007-08-25 01:37:05 +00002403 vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
ths70848512007-08-25 01:37:05 +00002404}
2405
ths8d5d2d42007-08-25 01:37:51 +00002406
ths60fe76f2007-12-16 03:02:09 +00002407static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
ths70848512007-08-25 01:37:05 +00002408{
2409 /* We only advertise 1 auth scheme at a time, so client
2410 * must pick the one we sent. Verify this */
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002411 if (data[0] != vs->auth) { /* Reject auth */
aliguori1263b7d2009-03-06 20:27:32 +00002412 VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
ths70848512007-08-25 01:37:05 +00002413 vnc_write_u32(vs, 1);
2414 if (vs->minor >= 8) {
2415 static const char err[] = "Authentication failed";
2416 vnc_write_u32(vs, sizeof(err));
2417 vnc_write(vs, err, sizeof(err));
2418 }
2419 vnc_client_error(vs);
2420 } else { /* Accept requested auth */
2421 VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002422 switch (vs->auth) {
ths70848512007-08-25 01:37:05 +00002423 case VNC_AUTH_NONE:
2424 VNC_DEBUG("Accept auth none\n");
balroga26c97a2007-10-31 01:58:56 +00002425 if (vs->minor >= 8) {
2426 vnc_write_u32(vs, 0); /* Accept auth completion */
2427 vnc_flush(vs);
2428 }
aliguori5fb6c7a2009-03-06 20:27:23 +00002429 start_client_init(vs);
ths70848512007-08-25 01:37:05 +00002430 break;
2431
2432 case VNC_AUTH_VNC:
2433 VNC_DEBUG("Start VNC auth\n");
aliguori5fb6c7a2009-03-06 20:27:23 +00002434 start_auth_vnc(vs);
2435 break;
ths70848512007-08-25 01:37:05 +00002436
blueswir1eb38c522008-09-06 17:47:39 +00002437#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002438 case VNC_AUTH_VENCRYPT:
Dong Xu Wang3a931132011-11-29 16:52:38 +08002439 VNC_DEBUG("Accept VeNCrypt auth\n");
aliguori5fb6c7a2009-03-06 20:27:23 +00002440 start_auth_vencrypt(vs);
2441 break;
ths8d5d2d42007-08-25 01:37:51 +00002442#endif /* CONFIG_VNC_TLS */
2443
aliguori2f9606b2009-03-06 20:27:28 +00002444#ifdef CONFIG_VNC_SASL
2445 case VNC_AUTH_SASL:
2446 VNC_DEBUG("Accept SASL auth\n");
2447 start_auth_sasl(vs);
2448 break;
2449#endif /* CONFIG_VNC_SASL */
2450
ths70848512007-08-25 01:37:05 +00002451 default: /* Should not be possible, but just in case */
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002452 VNC_DEBUG("Reject auth %d server code bug\n", vs->auth);
ths70848512007-08-25 01:37:05 +00002453 vnc_write_u8(vs, 1);
2454 if (vs->minor >= 8) {
2455 static const char err[] = "Authentication failed";
2456 vnc_write_u32(vs, sizeof(err));
2457 vnc_write(vs, err, sizeof(err));
2458 }
2459 vnc_client_error(vs);
2460 }
2461 }
2462 return 0;
2463}
2464
ths60fe76f2007-12-16 03:02:09 +00002465static int protocol_version(VncState *vs, uint8_t *version, size_t len)
ths70848512007-08-25 01:37:05 +00002466{
2467 char local[13];
2468
2469 memcpy(local, version, 12);
2470 local[12] = 0;
2471
2472 if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
aliguori28a76be2009-03-06 20:27:40 +00002473 VNC_DEBUG("Malformed protocol version %s\n", local);
2474 vnc_client_error(vs);
2475 return 0;
ths70848512007-08-25 01:37:05 +00002476 }
2477 VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2478 if (vs->major != 3 ||
aliguori28a76be2009-03-06 20:27:40 +00002479 (vs->minor != 3 &&
2480 vs->minor != 4 &&
2481 vs->minor != 5 &&
2482 vs->minor != 7 &&
2483 vs->minor != 8)) {
2484 VNC_DEBUG("Unsupported client version\n");
2485 vnc_write_u32(vs, VNC_AUTH_INVALID);
2486 vnc_flush(vs);
2487 vnc_client_error(vs);
2488 return 0;
ths70848512007-08-25 01:37:05 +00002489 }
thsb0566f42007-09-30 13:01:15 +00002490 /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
ths70848512007-08-25 01:37:05 +00002491 * as equivalent to v3.3 by servers
2492 */
thsb0566f42007-09-30 13:01:15 +00002493 if (vs->minor == 4 || vs->minor == 5)
aliguori28a76be2009-03-06 20:27:40 +00002494 vs->minor = 3;
ths70848512007-08-25 01:37:05 +00002495
2496 if (vs->minor == 3) {
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002497 if (vs->auth == VNC_AUTH_NONE) {
ths70848512007-08-25 01:37:05 +00002498 VNC_DEBUG("Tell client auth none\n");
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002499 vnc_write_u32(vs, vs->auth);
ths70848512007-08-25 01:37:05 +00002500 vnc_flush(vs);
aliguori28a76be2009-03-06 20:27:40 +00002501 start_client_init(vs);
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002502 } else if (vs->auth == VNC_AUTH_VNC) {
ths70848512007-08-25 01:37:05 +00002503 VNC_DEBUG("Tell client VNC auth\n");
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002504 vnc_write_u32(vs, vs->auth);
ths70848512007-08-25 01:37:05 +00002505 vnc_flush(vs);
2506 start_auth_vnc(vs);
2507 } else {
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002508 VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
ths70848512007-08-25 01:37:05 +00002509 vnc_write_u32(vs, VNC_AUTH_INVALID);
2510 vnc_flush(vs);
2511 vnc_client_error(vs);
2512 }
2513 } else {
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002514 VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
aliguori28a76be2009-03-06 20:27:40 +00002515 vnc_write_u8(vs, 1); /* num auth */
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002516 vnc_write_u8(vs, vs->auth);
aliguori28a76be2009-03-06 20:27:40 +00002517 vnc_read_when(vs, protocol_client_auth, 1);
2518 vnc_flush(vs);
ths70848512007-08-25 01:37:05 +00002519 }
bellard24236862006-04-30 21:28:36 +00002520
2521 return 0;
2522}
2523
Corentin Chary999342a2011-02-04 09:05:55 +01002524static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
2525{
2526 struct VncSurface *vs = &vd->guest;
2527
2528 return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
2529}
2530
Corentin Chary7d964c92011-02-04 09:05:56 +01002531void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
2532{
2533 int i, j;
2534
2535 w = (x + w) / VNC_STAT_RECT;
2536 h = (y + h) / VNC_STAT_RECT;
2537 x /= VNC_STAT_RECT;
2538 y /= VNC_STAT_RECT;
2539
Corentin Chary207f3282011-02-04 09:06:03 +01002540 for (j = y; j <= h; j++) {
2541 for (i = x; i <= w; i++) {
Corentin Chary7d964c92011-02-04 09:05:56 +01002542 vs->lossy_rect[j][i] = 1;
2543 }
2544 }
2545}
2546
2547static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
2548{
2549 VncState *vs;
2550 int sty = y / VNC_STAT_RECT;
2551 int stx = x / VNC_STAT_RECT;
2552 int has_dirty = 0;
2553
2554 y = y / VNC_STAT_RECT * VNC_STAT_RECT;
2555 x = x / VNC_STAT_RECT * VNC_STAT_RECT;
2556
2557 QTAILQ_FOREACH(vs, &vd->clients, next) {
Corentin Charybc2429b2011-02-04 09:06:05 +01002558 int j;
Corentin Chary7d964c92011-02-04 09:05:56 +01002559
2560 /* kernel send buffers are full -> refresh later */
2561 if (vs->output.offset) {
2562 continue;
2563 }
2564
2565 if (!vs->lossy_rect[sty][stx]) {
2566 continue;
2567 }
Corentin Chary207f3282011-02-04 09:06:03 +01002568
Corentin Chary7d964c92011-02-04 09:05:56 +01002569 vs->lossy_rect[sty][stx] = 0;
2570 for (j = 0; j < VNC_STAT_RECT; ++j) {
Peter Lievenb4c85dd2014-01-08 10:08:33 +01002571 bitmap_set(vs->dirty[y + j],
2572 x / VNC_DIRTY_PIXELS_PER_BIT,
2573 VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT);
Corentin Chary7d964c92011-02-04 09:05:56 +01002574 }
2575 has_dirty++;
2576 }
Corentin Chary207f3282011-02-04 09:06:03 +01002577
Corentin Chary7d964c92011-02-04 09:05:56 +01002578 return has_dirty;
2579}
2580
2581static int vnc_update_stats(VncDisplay *vd, struct timeval * tv)
Corentin Chary999342a2011-02-04 09:05:55 +01002582{
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002583 int width = pixman_image_get_width(vd->guest.fb);
2584 int height = pixman_image_get_height(vd->guest.fb);
Corentin Chary999342a2011-02-04 09:05:55 +01002585 int x, y;
2586 struct timeval res;
Corentin Chary7d964c92011-02-04 09:05:56 +01002587 int has_dirty = 0;
Corentin Chary999342a2011-02-04 09:05:55 +01002588
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002589 for (y = 0; y < height; y += VNC_STAT_RECT) {
2590 for (x = 0; x < width; x += VNC_STAT_RECT) {
Corentin Chary999342a2011-02-04 09:05:55 +01002591 VncRectStat *rect = vnc_stat_rect(vd, x, y);
2592
2593 rect->updated = false;
2594 }
2595 }
2596
Blue Swirlad620c22011-03-13 10:30:52 +00002597 qemu_timersub(tv, &VNC_REFRESH_STATS, &res);
Corentin Chary999342a2011-02-04 09:05:55 +01002598
2599 if (timercmp(&vd->guest.last_freq_check, &res, >)) {
Corentin Chary7d964c92011-02-04 09:05:56 +01002600 return has_dirty;
Corentin Chary999342a2011-02-04 09:05:55 +01002601 }
2602 vd->guest.last_freq_check = *tv;
2603
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002604 for (y = 0; y < height; y += VNC_STAT_RECT) {
2605 for (x = 0; x < width; x += VNC_STAT_RECT) {
Corentin Chary999342a2011-02-04 09:05:55 +01002606 VncRectStat *rect= vnc_stat_rect(vd, x, y);
2607 int count = ARRAY_SIZE(rect->times);
2608 struct timeval min, max;
2609
2610 if (!timerisset(&rect->times[count - 1])) {
2611 continue ;
2612 }
2613
2614 max = rect->times[(rect->idx + count - 1) % count];
Blue Swirlad620c22011-03-13 10:30:52 +00002615 qemu_timersub(tv, &max, &res);
Corentin Chary999342a2011-02-04 09:05:55 +01002616
2617 if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) {
2618 rect->freq = 0;
Corentin Chary7d964c92011-02-04 09:05:56 +01002619 has_dirty += vnc_refresh_lossy_rect(vd, x, y);
Corentin Chary999342a2011-02-04 09:05:55 +01002620 memset(rect->times, 0, sizeof (rect->times));
2621 continue ;
2622 }
2623
2624 min = rect->times[rect->idx];
2625 max = rect->times[(rect->idx + count - 1) % count];
Blue Swirlad620c22011-03-13 10:30:52 +00002626 qemu_timersub(&max, &min, &res);
Corentin Chary999342a2011-02-04 09:05:55 +01002627
2628 rect->freq = res.tv_sec + res.tv_usec / 1000000.;
2629 rect->freq /= count;
2630 rect->freq = 1. / rect->freq;
2631 }
2632 }
Corentin Chary7d964c92011-02-04 09:05:56 +01002633 return has_dirty;
Corentin Chary999342a2011-02-04 09:05:55 +01002634}
2635
2636double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
2637{
2638 int i, j;
2639 double total = 0;
2640 int num = 0;
2641
2642 x = (x / VNC_STAT_RECT) * VNC_STAT_RECT;
2643 y = (y / VNC_STAT_RECT) * VNC_STAT_RECT;
2644
2645 for (j = y; j <= y + h; j += VNC_STAT_RECT) {
2646 for (i = x; i <= x + w; i += VNC_STAT_RECT) {
2647 total += vnc_stat_rect(vs->vd, i, j)->freq;
2648 num++;
2649 }
2650 }
2651
2652 if (num) {
2653 return total / num;
2654 } else {
2655 return 0;
2656 }
2657}
2658
2659static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
2660{
2661 VncRectStat *rect;
2662
2663 rect = vnc_stat_rect(vd, x, y);
2664 if (rect->updated) {
2665 return ;
2666 }
2667 rect->times[rect->idx] = *tv;
2668 rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times);
2669 rect->updated = true;
2670}
2671
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002672static int vnc_refresh_server_surface(VncDisplay *vd)
2673{
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002674 int width = pixman_image_get_width(vd->guest.fb);
2675 int height = pixman_image_get_height(vd->guest.fb);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002676 int y;
Peter Lieven12b316d2014-01-08 10:08:35 +01002677 uint8_t *guest_row0 = NULL, *server_row0;
2678 int guest_stride = 0, server_stride;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002679 int cmp_bytes;
Amit Shah41b4bef2010-02-05 16:34:05 +05302680 VncState *vs;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002681 int has_dirty = 0;
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002682 pixman_image_t *tmpbuf = NULL;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002683
Corentin Chary80e0c8c2011-02-04 09:06:08 +01002684 struct timeval tv = { 0, 0 };
Corentin Chary999342a2011-02-04 09:05:55 +01002685
Corentin Chary80e0c8c2011-02-04 09:06:08 +01002686 if (!vd->non_adaptive) {
2687 gettimeofday(&tv, NULL);
2688 has_dirty = vnc_update_stats(vd, &tv);
2689 }
Corentin Chary999342a2011-02-04 09:05:55 +01002690
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002691 /*
2692 * Walk through the guest dirty map.
2693 * Check and copy modified bits from guest to server surface.
2694 * Update server dirty map.
2695 */
Peter Lieven6cd859a2014-01-08 10:08:34 +01002696 cmp_bytes = VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES;
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002697 if (cmp_bytes > vnc_server_fb_stride(vd)) {
2698 cmp_bytes = vnc_server_fb_stride(vd);
Stefan Weil9e4dd562012-03-14 07:58:48 +01002699 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002700 if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
2701 int width = pixman_image_get_width(vd->server);
2702 tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
Peter Lieven12b316d2014-01-08 10:08:35 +01002703 } else {
2704 guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
2705 guest_stride = pixman_image_get_stride(vd->guest.fb);
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002706 }
Peter Lieven12b316d2014-01-08 10:08:35 +01002707 server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
2708 server_stride = pixman_image_get_stride(vd->server);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002709
Peter Lieven12b316d2014-01-08 10:08:35 +01002710 y = 0;
2711 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) {
2736 if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
2737 continue;
2738 }
2739 if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0) {
2740 continue;
2741 }
2742 memcpy(server_ptr, guest_ptr, cmp_bytes);
2743 if (!vd->non_adaptive) {
2744 vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
2745 y, &tv);
2746 }
2747 QTAILQ_FOREACH(vs, &vd->clients, next) {
2748 set_bit(x, vs->dirty[y]);
2749 }
2750 has_dirty++;
2751 }
2752
2753 y++;
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002754 }
Gerd Hoffmann9f649162012-10-10 13:29:43 +02002755 qemu_pixman_image_unref(tmpbuf);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002756 return has_dirty;
2757}
2758
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002759static void vnc_refresh(DisplayChangeListener *dcl)
Stefano Stabellini703bc682009-08-03 10:54:05 +01002760{
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002761 VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
Amit Shah41b4bef2010-02-05 16:34:05 +05302762 VncState *vs, *vn;
2763 int has_dirty, rects = 0;
Stefano Stabellini703bc682009-08-03 10:54:05 +01002764
Gerd Hoffmann1dbfa002013-03-12 13:44:38 +01002765 graphic_hw_update(NULL);
Stefano Stabellini703bc682009-08-03 10:54:05 +01002766
Corentin Charybd023f92010-07-07 20:58:02 +02002767 if (vnc_trylock_display(vd)) {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002768 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
Corentin Charybd023f92010-07-07 20:58:02 +02002769 return;
2770 }
2771
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002772 has_dirty = vnc_refresh_server_surface(vd);
Corentin Charybd023f92010-07-07 20:58:02 +02002773 vnc_unlock_display(vd);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002774
Amit Shah41b4bef2010-02-05 16:34:05 +05302775 QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
Gerd Hoffmann38ee14f2014-03-06 13:54:28 +01002776 rects += vnc_update_client(vs, has_dirty, false);
Stefano Stabellini6185c572010-01-25 12:54:57 +00002777 /* vs might be free()ed here */
Stefano Stabellini703bc682009-08-03 10:54:05 +01002778 }
Corentin Charybd023f92010-07-07 20:58:02 +02002779
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002780 if (QTAILQ_EMPTY(&vd->clients)) {
2781 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX);
Stefano Stabellini83755c12010-01-11 17:30:50 +00002782 return;
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002783 }
Stefano Stabellini703bc682009-08-03 10:54:05 +01002784
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002785 if (has_dirty && rects) {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002786 vd->dcl.update_interval /= 2;
2787 if (vd->dcl.update_interval < VNC_REFRESH_INTERVAL_BASE) {
2788 vd->dcl.update_interval = VNC_REFRESH_INTERVAL_BASE;
2789 }
Stefano Stabellini2430ffe2009-08-03 10:56:01 +01002790 } else {
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002791 vd->dcl.update_interval += VNC_REFRESH_INTERVAL_INC;
2792 if (vd->dcl.update_interval > VNC_REFRESH_INTERVAL_MAX) {
2793 vd->dcl.update_interval = VNC_REFRESH_INTERVAL_MAX;
2794 }
Stefano Stabellini703bc682009-08-03 10:54:05 +01002795 }
2796}
2797
Michael Tokarev2c8cf542013-06-11 15:42:44 +04002798static void vnc_connect(VncDisplay *vd, int csock,
2799 bool skipauth, bool websocket)
balrog3aa3eea2008-02-03 02:54:04 +00002800{
Anthony Liguori7267c092011-08-20 22:09:37 -05002801 VncState *vs = g_malloc0(sizeof(VncState));
Corentin Chary7d964c92011-02-04 09:05:56 +01002802 int i;
2803
aliguori753b4052009-02-16 14:59:30 +00002804 vs->csock = csock;
Daniel P. Berrange7e7e2eb2011-06-23 13:31:41 +01002805
2806 if (skipauth) {
2807 vs->auth = VNC_AUTH_NONE;
2808#ifdef CONFIG_VNC_TLS
2809 vs->subauth = VNC_AUTH_INVALID;
2810#endif
2811 } else {
2812 vs->auth = vd->auth;
2813#ifdef CONFIG_VNC_TLS
2814 vs->subauth = vd->subauth;
2815#endif
2816 }
2817
Anthony Liguori7267c092011-08-20 22:09:37 -05002818 vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
Corentin Chary7d964c92011-02-04 09:05:56 +01002819 for (i = 0; i < VNC_STAT_ROWS; ++i) {
Anthony Liguori7267c092011-08-20 22:09:37 -05002820 vs->lossy_rect[i] = g_malloc0(VNC_STAT_COLS * sizeof (uint8_t));
Corentin Chary7d964c92011-02-04 09:05:56 +01002821 }
aliguori753b4052009-02-16 14:59:30 +00002822
2823 VNC_DEBUG("New client on socket %d\n", csock);
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002824 update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
Stefan Hajnoczif9e8cac2013-03-27 10:10:43 +01002825 qemu_set_nonblock(vs->csock);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002826#ifdef CONFIG_VNC_WS
2827 if (websocket) {
2828 vs->websocket = 1;
Tim Hardeck0057a0d2013-04-23 16:33:01 +02002829#ifdef CONFIG_VNC_TLS
2830 if (vd->tls.x509cert) {
2831 qemu_set_fd_handler2(vs->csock, NULL, vncws_tls_handshake_peek,
2832 NULL, vs);
2833 } else
2834#endif /* CONFIG_VNC_TLS */
2835 {
2836 qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read,
2837 NULL, vs);
2838 }
Tim Hardeck7536ee42013-01-21 11:04:44 +01002839 } else
2840#endif /* CONFIG_VNC_WS */
2841 {
2842 qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
2843 }
aliguori753b4052009-02-16 14:59:30 +00002844
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002845 vnc_client_cache_addr(vs);
Luiz Capitulino586153d2010-01-14 14:50:57 -02002846 vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01002847 vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
Luiz Capitulino4a80dba2010-01-14 14:50:56 -02002848
aliguori753b4052009-02-16 14:59:30 +00002849 vs->vd = vd;
Tim Hardeck7536ee42013-01-21 11:04:44 +01002850
2851#ifdef CONFIG_VNC_WS
2852 if (!vs->websocket)
2853#endif
2854 {
2855 vnc_init_state(vs);
2856 }
2857}
2858
2859void vnc_init_state(VncState *vs)
2860{
Tim Hardeck6fd8e792013-01-21 11:04:45 +01002861 vs->initialized = true;
Tim Hardeck7536ee42013-01-21 11:04:44 +01002862 VncDisplay *vd = vs->vd;
2863
aliguori753b4052009-02-16 14:59:30 +00002864 vs->last_x = -1;
2865 vs->last_y = -1;
2866
2867 vs->as.freq = 44100;
2868 vs->as.nchannels = 2;
2869 vs->as.fmt = AUD_FMT_S16;
2870 vs->as.endianness = 0;
2871
Corentin Charybd023f92010-07-07 20:58:02 +02002872 qemu_mutex_init(&vs->output_mutex);
Corentin Chary175b2a62012-03-14 07:58:47 +01002873 vs->bh = qemu_bh_new(vnc_jobs_bh, vs);
Corentin Charybd023f92010-07-07 20:58:02 +02002874
Amit Shah41b4bef2010-02-05 16:34:05 +05302875 QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002876
Gerd Hoffmann1dbfa002013-03-12 13:44:38 +01002877 graphic_hw_update(NULL);
Stefano Stabellini1fc62412009-08-03 10:54:32 +01002878
balrog3aa3eea2008-02-03 02:54:04 +00002879 vnc_write(vs, "RFB 003.008\n", 12);
2880 vnc_flush(vs);
2881 vnc_read_when(vs, protocol_version, 12);
malc53762dd2008-12-01 20:57:52 +00002882 reset_keys(vs);
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01002883 if (vs->vd->lock_key_sync)
2884 vs->led = qemu_add_led_event_handler(kbd_leds, vs);
aliguori753b4052009-02-16 14:59:30 +00002885
Anthony Liguori37c34d92010-03-10 09:38:29 -06002886 vs->mouse_mode_notifier.notify = check_pointer_type_change;
2887 qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
2888
Gerd Hoffmann198a0032009-06-16 14:19:48 +02002889 /* vs might be free()ed here */
balrog3aa3eea2008-02-03 02:54:04 +00002890}
2891
Tim Hardeck7536ee42013-01-21 11:04:44 +01002892static void vnc_listen_read(void *opaque, bool websocket)
bellard24236862006-04-30 21:28:36 +00002893{
aliguori753b4052009-02-16 14:59:30 +00002894 VncDisplay *vs = opaque;
bellard24236862006-04-30 21:28:36 +00002895 struct sockaddr_in addr;
2896 socklen_t addrlen = sizeof(addr);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002897 int csock;
bellard24236862006-04-30 21:28:36 +00002898
balrog9f60ad52008-01-14 21:45:55 +00002899 /* Catch-up */
Gerd Hoffmann1dbfa002013-03-12 13:44:38 +01002900 graphic_hw_update(NULL);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002901#ifdef CONFIG_VNC_WS
2902 if (websocket) {
2903 csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen);
2904 } else
2905#endif /* CONFIG_VNC_WS */
2906 {
2907 csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
2908 }
balrog9f60ad52008-01-14 21:45:55 +00002909
aliguori753b4052009-02-16 14:59:30 +00002910 if (csock != -1) {
Michael Tokarev2c8cf542013-06-11 15:42:44 +04002911 vnc_connect(vs, csock, false, websocket);
bellard24236862006-04-30 21:28:36 +00002912 }
2913}
2914
Tim Hardeck7536ee42013-01-21 11:04:44 +01002915static void vnc_listen_regular_read(void *opaque)
2916{
Michael Tokarev2c8cf542013-06-11 15:42:44 +04002917 vnc_listen_read(opaque, false);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002918}
2919
2920#ifdef CONFIG_VNC_WS
2921static void vnc_listen_websocket_read(void *opaque)
2922{
Michael Tokarev2c8cf542013-06-11 15:42:44 +04002923 vnc_listen_read(opaque, true);
Tim Hardeck7536ee42013-01-21 11:04:44 +01002924}
2925#endif /* CONFIG_VNC_WS */
2926
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01002927static const DisplayChangeListenerOps dcl_ops = {
2928 .dpy_name = "vnc",
Gerd Hoffmann0f7b2862013-03-14 11:56:16 +01002929 .dpy_refresh = vnc_refresh,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01002930 .dpy_gfx_copy = vnc_dpy_copy,
2931 .dpy_gfx_update = vnc_dpy_update,
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +01002932 .dpy_gfx_switch = vnc_dpy_switch,
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01002933 .dpy_mouse_set = vnc_mouse_set,
2934 .dpy_cursor_define = vnc_dpy_cursor_define,
2935};
2936
ths71cab5c2007-08-25 01:35:38 +00002937void vnc_display_init(DisplayState *ds)
bellard24236862006-04-30 21:28:36 +00002938{
Anthony Liguori7267c092011-08-20 22:09:37 -05002939 VncDisplay *vs = g_malloc0(sizeof(*vs));
bellard24236862006-04-30 21:28:36 +00002940
aliguori753b4052009-02-16 14:59:30 +00002941 vnc_display = vs;
bellard24236862006-04-30 21:28:36 +00002942
2943 vs->lsock = -1;
Tim Hardeck7536ee42013-01-21 11:04:44 +01002944#ifdef CONFIG_VNC_WS
2945 vs->lwebsock = -1;
2946#endif
bellard24236862006-04-30 21:28:36 +00002947
Amit Shah41b4bef2010-02-05 16:34:05 +05302948 QTAILQ_INIT(&vs->clients);
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02002949 vs->expires = TIME_MAX;
bellard24236862006-04-30 21:28:36 +00002950
Gerd Hoffmann40066172014-05-21 13:18:20 +02002951 if (keyboard_layout) {
2952 trace_vnc_key_map_init(keyboard_layout);
aliguori04837552009-03-06 20:27:10 +00002953 vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
Gerd Hoffmann40066172014-05-21 13:18:20 +02002954 } else {
aliguori04837552009-03-06 20:27:10 +00002955 vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
Gerd Hoffmann40066172014-05-21 13:18:20 +02002956 }
bellard24236862006-04-30 21:28:36 +00002957
bellard24236862006-04-30 21:28:36 +00002958 if (!vs->kbd_layout)
aliguori28a76be2009-03-06 20:27:40 +00002959 exit(1);
bellard24236862006-04-30 21:28:36 +00002960
Corentin Charybd023f92010-07-07 20:58:02 +02002961 qemu_mutex_init(&vs->mutex);
2962 vnc_start_worker_thread();
Corentin Charybd023f92010-07-07 20:58:02 +02002963
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01002964 vs->dcl.ops = &dcl_ops;
Gerd Hoffmann52090892013-04-23 15:44:31 +02002965 register_displaychangelistener(&vs->dcl);
ths71cab5c2007-08-25 01:35:38 +00002966}
ths73fc9742006-12-22 02:09:07 +00002967
ths6f430242007-08-25 01:39:57 +00002968
Blue Swirl71a8cde2012-10-28 11:04:48 +00002969static void vnc_display_close(DisplayState *ds)
ths71cab5c2007-08-25 01:35:38 +00002970{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01002971 VncDisplay *vs = vnc_display;
ths71cab5c2007-08-25 01:35:38 +00002972
aliguori452b4d82009-02-11 21:00:38 +00002973 if (!vs)
2974 return;
ths71cab5c2007-08-25 01:35:38 +00002975 if (vs->display) {
Anthony Liguori7267c092011-08-20 22:09:37 -05002976 g_free(vs->display);
aliguori28a76be2009-03-06 20:27:40 +00002977 vs->display = NULL;
ths71cab5c2007-08-25 01:35:38 +00002978 }
2979 if (vs->lsock != -1) {
aliguori28a76be2009-03-06 20:27:40 +00002980 qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
2981 close(vs->lsock);
2982 vs->lsock = -1;
ths71cab5c2007-08-25 01:35:38 +00002983 }
Tim Hardeck7536ee42013-01-21 11:04:44 +01002984#ifdef CONFIG_VNC_WS
2985 g_free(vs->ws_display);
2986 vs->ws_display = NULL;
2987 if (vs->lwebsock != -1) {
2988 qemu_set_fd_handler2(vs->lwebsock, NULL, NULL, NULL, NULL);
2989 close(vs->lwebsock);
2990 vs->lwebsock = -1;
2991 }
2992#endif /* CONFIG_VNC_WS */
ths70848512007-08-25 01:37:05 +00002993 vs->auth = VNC_AUTH_INVALID;
blueswir1eb38c522008-09-06 17:47:39 +00002994#ifdef CONFIG_VNC_TLS
ths8d5d2d42007-08-25 01:37:51 +00002995 vs->subauth = VNC_AUTH_INVALID;
aliguori5fb6c7a2009-03-06 20:27:23 +00002996 vs->tls.x509verify = 0;
ths8d5d2d42007-08-25 01:37:51 +00002997#endif
ths71cab5c2007-08-25 01:35:38 +00002998}
2999
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003000int vnc_display_password(DisplayState *ds, const char *password)
3001{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003002 VncDisplay *vs = vnc_display;
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003003
3004 if (!vs) {
Luiz Capitulinoa6aa9d32011-12-07 10:19:10 -02003005 return -EINVAL;
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003006 }
Gerd Hoffmanncf864562013-12-11 13:15:37 +01003007 if (vs->auth == VNC_AUTH_NONE) {
3008 error_printf_unless_qmp("If you want use passwords please enable "
3009 "password auth using '-vnc ${dpy},password'.");
3010 return -EINVAL;
Anthony Liguori1cd20f82011-01-31 14:27:36 -06003011 }
3012
3013 if (vs->password) {
Anthony Liguori7267c092011-08-20 22:09:37 -05003014 g_free(vs->password);
aliguori28a76be2009-03-06 20:27:40 +00003015 vs->password = NULL;
ths70848512007-08-25 01:37:05 +00003016 }
Gerd Hoffmanncf864562013-12-11 13:15:37 +01003017 if (password) {
3018 vs->password = g_strdup(password);
Daniel P. Berrange7dfbfc72012-02-14 12:37:29 +00003019 }
Luiz Capitulinoa6aa9d32011-12-07 10:19:10 -02003020
3021 return 0;
ths70848512007-08-25 01:37:05 +00003022}
3023
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003024int vnc_display_pw_expire(DisplayState *ds, time_t expires)
3025{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003026 VncDisplay *vs = vnc_display;
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003027
Gerd Hoffmann1643f2b2012-05-24 10:55:01 +02003028 if (!vs) {
3029 return -EINVAL;
3030 }
3031
Gerd Hoffmann3c9405a2010-10-07 11:50:45 +02003032 vs->expires = expires;
3033 return 0;
3034}
3035
Anthony Liguorif92f8af2009-05-20 13:01:02 -05003036char *vnc_display_local_addr(DisplayState *ds)
3037{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003038 VncDisplay *vs = vnc_display;
Anthony Liguorif92f8af2009-05-20 13:01:02 -05003039
3040 return vnc_socket_local_addr("%s:%s", vs->lsock);
3041}
3042
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003043void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
ths71cab5c2007-08-25 01:35:38 +00003044{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003045 VncDisplay *vs = vnc_display;
ths70848512007-08-25 01:37:05 +00003046 const char *options;
3047 int password = 0;
balrog3aa3eea2008-02-03 02:54:04 +00003048 int reverse = 0;
blueswir1eb38c522008-09-06 17:47:39 +00003049#ifdef CONFIG_VNC_TLS
ths3a702692007-08-25 01:38:36 +00003050 int tls = 0, x509 = 0;
ths8d5d2d42007-08-25 01:37:51 +00003051#endif
aliguori2f9606b2009-03-06 20:27:28 +00003052#ifdef CONFIG_VNC_SASL
3053 int sasl = 0;
3054 int saslErr;
3055#endif
Blue Swirl2ded6ad2010-10-13 18:38:08 +00003056#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
aliguori76655d62009-03-06 20:27:37 +00003057 int acl = 0;
Blue Swirl2ded6ad2010-10-13 18:38:08 +00003058#endif
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01003059 int lock_key_sync = 1;
ths71cab5c2007-08-25 01:35:38 +00003060
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003061 if (!vnc_display) {
3062 error_setg(errp, "VNC display not active");
3063 return;
3064 }
ths71cab5c2007-08-25 01:35:38 +00003065 vnc_display_close(ds);
ths70848512007-08-25 01:37:05 +00003066 if (strcmp(display, "none") == 0)
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003067 return;
ths71cab5c2007-08-25 01:35:38 +00003068
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003069 vs->display = g_strdup(display);
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01003070 vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
ths70848512007-08-25 01:37:05 +00003071
3072 options = display;
3073 while ((options = strchr(options, ','))) {
aliguori28a76be2009-03-06 20:27:40 +00003074 options++;
3075 if (strncmp(options, "password", 8) == 0) {
Paul Moore0f669982012-08-03 14:39:21 -04003076 if (fips_get_state()) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003077 error_setg(errp,
3078 "VNC password auth disabled due to FIPS mode, "
3079 "consider using the VeNCrypt or SASL authentication "
3080 "methods as an alternative");
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003081 goto fail;
Paul Moore0f669982012-08-03 14:39:21 -04003082 }
aliguori28a76be2009-03-06 20:27:40 +00003083 password = 1; /* Require password auth */
3084 } else if (strncmp(options, "reverse", 7) == 0) {
3085 reverse = 1;
Stefan Hajnoczicee8e6a2012-01-06 16:57:45 +00003086 } else if (strncmp(options, "no-lock-key-sync", 16) == 0) {
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01003087 lock_key_sync = 0;
aliguori2f9606b2009-03-06 20:27:28 +00003088#ifdef CONFIG_VNC_SASL
aliguori28a76be2009-03-06 20:27:40 +00003089 } else if (strncmp(options, "sasl", 4) == 0) {
3090 sasl = 1; /* Require SASL auth */
aliguori2f9606b2009-03-06 20:27:28 +00003091#endif
Tim Hardeck7536ee42013-01-21 11:04:44 +01003092#ifdef CONFIG_VNC_WS
3093 } else if (strncmp(options, "websocket", 9) == 0) {
3094 char *start, *end;
3095 vs->websocket = 1;
3096
3097 /* Check for 'websocket=<port>' */
3098 start = strchr(options, '=');
3099 end = strchr(options, ',');
3100 if (start && (!end || (start < end))) {
3101 int len = end ? end-(start+1) : strlen(start+1);
3102 if (len < 6) {
3103 /* extract the host specification from display */
3104 char *host = NULL, *port = NULL, *host_end = NULL;
3105 port = g_strndup(start + 1, len);
3106
3107 /* ipv6 hosts have colons */
3108 end = strchr(display, ',');
3109 host_end = g_strrstr_len(display, end - display, ":");
3110
3111 if (host_end) {
3112 host = g_strndup(display, host_end - display + 1);
3113 } else {
3114 host = g_strndup(":", 1);
3115 }
3116 vs->ws_display = g_strconcat(host, port, NULL);
3117 g_free(host);
3118 g_free(port);
3119 }
3120 }
3121#endif /* CONFIG_VNC_WS */
blueswir1eb38c522008-09-06 17:47:39 +00003122#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003123 } else if (strncmp(options, "tls", 3) == 0) {
3124 tls = 1; /* Require TLS */
3125 } else if (strncmp(options, "x509", 4) == 0) {
3126 char *start, *end;
3127 x509 = 1; /* Require x509 certificates */
3128 if (strncmp(options, "x509verify", 10) == 0)
3129 vs->tls.x509verify = 1; /* ...and verify client certs */
ths6f430242007-08-25 01:39:57 +00003130
aliguori28a76be2009-03-06 20:27:40 +00003131 /* Now check for 'x509=/some/path' postfix
3132 * and use that to setup x509 certificate/key paths */
3133 start = strchr(options, '=');
3134 end = strchr(options, ',');
3135 if (start && (!end || (start < end))) {
3136 int len = end ? end-(start+1) : strlen(start+1);
Anthony Liguori7267c092011-08-20 22:09:37 -05003137 char *path = g_strndup(start + 1, len);
blueswir1be15b142008-10-25 11:21:28 +00003138
aliguori28a76be2009-03-06 20:27:40 +00003139 VNC_DEBUG("Trying certificate path '%s'\n", path);
3140 if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003141 error_setg(errp, "Failed to find x509 certificates/keys in %s", path);
Anthony Liguori7267c092011-08-20 22:09:37 -05003142 g_free(path);
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003143 goto fail;
aliguori28a76be2009-03-06 20:27:40 +00003144 }
Anthony Liguori7267c092011-08-20 22:09:37 -05003145 g_free(path);
aliguori28a76be2009-03-06 20:27:40 +00003146 } else {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003147 error_setg(errp, "No certificate path provided");
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003148 goto fail;
aliguori28a76be2009-03-06 20:27:40 +00003149 }
ths8d5d2d42007-08-25 01:37:51 +00003150#endif
Blue Swirl2ded6ad2010-10-13 18:38:08 +00003151#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
aliguori28a76be2009-03-06 20:27:40 +00003152 } else if (strncmp(options, "acl", 3) == 0) {
3153 acl = 1;
Blue Swirl2ded6ad2010-10-13 18:38:08 +00003154#endif
Corentin Chary6f9c78c2010-07-07 20:57:51 +02003155 } else if (strncmp(options, "lossy", 5) == 0) {
Peter Lievene22492d2014-01-08 10:08:38 +01003156#ifdef CONFIG_VNC_JPEG
Corentin Chary6f9c78c2010-07-07 20:57:51 +02003157 vs->lossy = true;
Peter Lievene22492d2014-01-08 10:08:38 +01003158#endif
Catalin Patulea7eff5742012-11-09 19:01:26 -05003159 } else if (strncmp(options, "non-adaptive", 12) == 0) {
Corentin Chary80e0c8c2011-02-04 09:06:08 +01003160 vs->non_adaptive = true;
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01003161 } else if (strncmp(options, "share=", 6) == 0) {
3162 if (strncmp(options+6, "ignore", 6) == 0) {
3163 vs->share_policy = VNC_SHARE_POLICY_IGNORE;
3164 } else if (strncmp(options+6, "allow-exclusive", 15) == 0) {
3165 vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
3166 } else if (strncmp(options+6, "force-shared", 12) == 0) {
3167 vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
3168 } else {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003169 error_setg(errp, "unknown vnc share= option");
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003170 goto fail;
Gerd Hoffmann8cf36482011-11-24 18:10:49 +01003171 }
aliguori28a76be2009-03-06 20:27:40 +00003172 }
ths70848512007-08-25 01:37:05 +00003173 }
3174
Peter Lievene22492d2014-01-08 10:08:38 +01003175 /* adaptive updates are only used with tight encoding and
3176 * if lossy updates are enabled so we can disable all the
3177 * calculations otherwise */
3178 if (!vs->lossy) {
3179 vs->non_adaptive = true;
3180 }
3181
aliguori76655d62009-03-06 20:27:37 +00003182#ifdef CONFIG_VNC_TLS
3183 if (acl && x509 && vs->tls.x509verify) {
aliguori28a76be2009-03-06 20:27:40 +00003184 if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
3185 fprintf(stderr, "Failed to create x509 dname ACL\n");
3186 exit(1);
3187 }
aliguori76655d62009-03-06 20:27:37 +00003188 }
3189#endif
3190#ifdef CONFIG_VNC_SASL
3191 if (acl && sasl) {
aliguori28a76be2009-03-06 20:27:40 +00003192 if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
3193 fprintf(stderr, "Failed to create username ACL\n");
3194 exit(1);
3195 }
aliguori76655d62009-03-06 20:27:37 +00003196 }
3197#endif
3198
aliguori2f9606b2009-03-06 20:27:28 +00003199 /*
3200 * Combinations we support here:
3201 *
3202 * - no-auth (clear text, no auth)
3203 * - password (clear text, weak auth)
3204 * - sasl (encrypt, good auth *IF* using Kerberos via GSSAPI)
3205 * - tls (encrypt, weak anonymous creds, no auth)
3206 * - tls + password (encrypt, weak anonymous creds, weak auth)
3207 * - tls + sasl (encrypt, weak anonymous creds, good auth)
3208 * - tls + x509 (encrypt, good x509 creds, no auth)
3209 * - tls + x509 + password (encrypt, good x509 creds, weak auth)
3210 * - tls + x509 + sasl (encrypt, good x509 creds, good auth)
3211 *
3212 * NB1. TLS is a stackable auth scheme.
3213 * NB2. the x509 schemes have option to validate a client cert dname
3214 */
ths70848512007-08-25 01:37:05 +00003215 if (password) {
blueswir1eb38c522008-09-06 17:47:39 +00003216#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003217 if (tls) {
3218 vs->auth = VNC_AUTH_VENCRYPT;
3219 if (x509) {
3220 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
3221 vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
3222 } else {
3223 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
3224 vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
3225 }
3226 } else {
aliguori2f9606b2009-03-06 20:27:28 +00003227#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00003228 VNC_DEBUG("Initializing VNC server with password auth\n");
3229 vs->auth = VNC_AUTH_VNC;
blueswir1eb38c522008-09-06 17:47:39 +00003230#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003231 vs->subauth = VNC_AUTH_INVALID;
3232 }
aliguori2f9606b2009-03-06 20:27:28 +00003233#endif /* CONFIG_VNC_TLS */
3234#ifdef CONFIG_VNC_SASL
3235 } else if (sasl) {
3236#ifdef CONFIG_VNC_TLS
3237 if (tls) {
3238 vs->auth = VNC_AUTH_VENCRYPT;
3239 if (x509) {
aliguori28a76be2009-03-06 20:27:40 +00003240 VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00003241 vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
3242 } else {
aliguori28a76be2009-03-06 20:27:40 +00003243 VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00003244 vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
3245 }
3246 } else {
3247#endif /* CONFIG_VNC_TLS */
aliguori28a76be2009-03-06 20:27:40 +00003248 VNC_DEBUG("Initializing VNC server with SASL auth\n");
aliguori2f9606b2009-03-06 20:27:28 +00003249 vs->auth = VNC_AUTH_SASL;
3250#ifdef CONFIG_VNC_TLS
3251 vs->subauth = VNC_AUTH_INVALID;
3252 }
3253#endif /* CONFIG_VNC_TLS */
3254#endif /* CONFIG_VNC_SASL */
ths70848512007-08-25 01:37:05 +00003255 } else {
blueswir1eb38c522008-09-06 17:47:39 +00003256#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003257 if (tls) {
3258 vs->auth = VNC_AUTH_VENCRYPT;
3259 if (x509) {
3260 VNC_DEBUG("Initializing VNC server with x509 no auth\n");
3261 vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
3262 } else {
3263 VNC_DEBUG("Initializing VNC server with TLS no auth\n");
3264 vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
3265 }
3266 } else {
ths8d5d2d42007-08-25 01:37:51 +00003267#endif
aliguori28a76be2009-03-06 20:27:40 +00003268 VNC_DEBUG("Initializing VNC server with no auth\n");
3269 vs->auth = VNC_AUTH_NONE;
blueswir1eb38c522008-09-06 17:47:39 +00003270#ifdef CONFIG_VNC_TLS
aliguori28a76be2009-03-06 20:27:40 +00003271 vs->subauth = VNC_AUTH_INVALID;
3272 }
ths8d5d2d42007-08-25 01:37:51 +00003273#endif
ths70848512007-08-25 01:37:05 +00003274 }
bellard24236862006-04-30 21:28:36 +00003275
aliguori2f9606b2009-03-06 20:27:28 +00003276#ifdef CONFIG_VNC_SASL
3277 if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003278 error_setg(errp, "Failed to initialize SASL auth: %s",
3279 sasl_errstring(saslErr, NULL, NULL));
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003280 goto fail;
aliguori2f9606b2009-03-06 20:27:28 +00003281 }
3282#endif
Gerd Hoffmann3a0558b2010-03-10 17:12:02 +01003283 vs->lock_key_sync = lock_key_sync;
aliguori2f9606b2009-03-06 20:27:28 +00003284
balrog3aa3eea2008-02-03 02:54:04 +00003285 if (reverse) {
aliguori9712eca2008-11-11 20:51:59 +00003286 /* connect to viewer */
Paolo Bonzini007fcd3e2012-10-18 09:01:01 +02003287 int csock;
3288 vs->lsock = -1;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003289#ifdef CONFIG_VNC_WS
3290 vs->lwebsock = -1;
3291#endif
Paolo Bonzini007fcd3e2012-10-18 09:01:01 +02003292 if (strncmp(display, "unix:", 5) == 0) {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003293 csock = unix_connect(display+5, errp);
balrog3aa3eea2008-02-03 02:54:04 +00003294 } else {
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003295 csock = inet_connect(display, errp);
balrog3aa3eea2008-02-03 02:54:04 +00003296 }
Paolo Bonzini007fcd3e2012-10-18 09:01:01 +02003297 if (csock < 0) {
3298 goto fail;
3299 }
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003300 vnc_connect(vs, csock, false, false);
aliguori9712eca2008-11-11 20:51:59 +00003301 } else {
3302 /* listen for connects */
3303 char *dpy;
Anthony Liguori7267c092011-08-20 22:09:37 -05003304 dpy = g_malloc(256);
aliguori9712eca2008-11-11 20:51:59 +00003305 if (strncmp(display, "unix:", 5) == 0) {
blueswir1bc575e92009-01-14 18:34:22 +00003306 pstrcpy(dpy, 256, "unix:");
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003307 vs->lsock = unix_listen(display+5, dpy+5, 256-5, errp);
aliguori9712eca2008-11-11 20:51:59 +00003308 } else {
Amos Kong029409e2012-05-11 00:28:26 +08003309 vs->lsock = inet_listen(display, dpy, 256,
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003310 SOCK_STREAM, 5900, errp);
Tim Hardeck7536ee42013-01-21 11:04:44 +01003311 if (vs->lsock < 0) {
3312 g_free(dpy);
3313 goto fail;
3314 }
3315#ifdef CONFIG_VNC_WS
3316 if (vs->websocket) {
3317 if (vs->ws_display) {
3318 vs->lwebsock = inet_listen(vs->ws_display, NULL, 256,
3319 SOCK_STREAM, 0, errp);
3320 } else {
3321 vs->lwebsock = inet_listen(vs->display, NULL, 256,
3322 SOCK_STREAM, 5700, errp);
3323 }
3324
3325 if (vs->lwebsock < 0) {
3326 if (vs->lsock) {
3327 close(vs->lsock);
3328 vs->lsock = -1;
3329 }
3330 g_free(dpy);
3331 goto fail;
3332 }
3333 }
3334#endif /* CONFIG_VNC_WS */
aliguori9712eca2008-11-11 20:51:59 +00003335 }
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003336 g_free(vs->display);
3337 vs->display = dpy;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003338 qemu_set_fd_handler2(vs->lsock, NULL,
3339 vnc_listen_regular_read, NULL, vs);
3340#ifdef CONFIG_VNC_WS
3341 if (vs->websocket) {
3342 qemu_set_fd_handler2(vs->lwebsock, NULL,
3343 vnc_listen_websocket_read, NULL, vs);
3344 }
3345#endif /* CONFIG_VNC_WS */
bellard24236862006-04-30 21:28:36 +00003346 }
Paolo Bonzini2d55f0e2012-10-02 10:17:21 +02003347 return;
Paolo Bonzini1ce52c72012-10-18 09:07:05 +02003348
3349fail:
3350 g_free(vs->display);
3351 vs->display = NULL;
Tim Hardeck7536ee42013-01-21 11:04:44 +01003352#ifdef CONFIG_VNC_WS
3353 g_free(vs->ws_display);
3354 vs->ws_display = NULL;
3355#endif /* CONFIG_VNC_WS */
bellard24236862006-04-30 21:28:36 +00003356}
Daniel P. Berrange13661082011-06-23 13:31:42 +01003357
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003358void vnc_display_add_client(DisplayState *ds, int csock, bool skipauth)
Daniel P. Berrange13661082011-06-23 13:31:42 +01003359{
Gerd Hoffmann21ef45d2013-02-28 11:34:31 +01003360 VncDisplay *vs = vnc_display;
Daniel P. Berrange13661082011-06-23 13:31:42 +01003361
Michael Tokarev2c8cf542013-06-11 15:42:44 +04003362 vnc_connect(vs, csock, skipauth, false);
Daniel P. Berrange13661082011-06-23 13:31:42 +01003363}