vnc.c 120.3 KB
Newer Older
B
bellard 已提交
1 2
/*
 * QEMU VNC display driver
3
 *
B
bellard 已提交
4 5
 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
 * Copyright (C) 2006 Fabrice Bellard
6
 * Copyright (C) 2009 Red Hat, Inc
7
 *
B
bellard 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

P
Peter Maydell 已提交
27
#include "qemu/osdep.h"
28
#include "vnc.h"
C
Corentin Chary 已提交
29
#include "vnc-jobs.h"
30
#include "trace.h"
31
#include "sysemu/sysemu.h"
32
#include "qemu/error-report.h"
33
#include "qemu/option.h"
34 35 36
#include "qemu/sockets.h"
#include "qemu/timer.h"
#include "qemu/acl.h"
37
#include "qemu/config-file.h"
38
#include "qapi/qapi-events.h"
39
#include "qapi/error.h"
40
#include "qapi/qapi-commands-ui.h"
41
#include "ui/input.h"
42
#include "crypto/hash.h"
43 44 45
#include "crypto/tlscredsanon.h"
#include "crypto/tlscredsx509.h"
#include "qom/object_interfaces.h"
46
#include "qemu/cutils.h"
47
#include "io/dns-resolver.h"
B
bellard 已提交
48

G
Gerd Hoffmann 已提交
49
#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
S
Stefano Stabellini 已提交
50
#define VNC_REFRESH_INTERVAL_INC  50
G
Gerd Hoffmann 已提交
51
#define VNC_REFRESH_INTERVAL_MAX  GUI_REFRESH_INTERVAL_IDLE
52 53
static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
B
bellard 已提交
54 55

#include "vnc_keysym.h"
56
#include "crypto/cipher.h"
57

G
Gerd Hoffmann 已提交
58 59
static QTAILQ_HEAD(, VncDisplay) vnc_displays =
    QTAILQ_HEAD_INITIALIZER(vnc_displays);
B
bellard 已提交
60

G
Gerd Hoffmann 已提交
61
static int vnc_cursor_define(VncState *vs);
62
static void vnc_release_modifiers(VncState *vs);
63
static void vnc_update_throttle_offset(VncState *vs);
G
Gerd Hoffmann 已提交
64

65 66 67 68 69 70 71 72 73 74
static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
{
#ifdef _VNC_DEBUG
    static const char *mn[] = {
        [0]                           = "undefined",
        [VNC_SHARE_MODE_CONNECTING]   = "connecting",
        [VNC_SHARE_MODE_SHARED]       = "shared",
        [VNC_SHARE_MODE_EXCLUSIVE]    = "exclusive",
        [VNC_SHARE_MODE_DISCONNECTED] = "disconnected",
    };
75 76
    fprintf(stderr, "%s/%p: %s -> %s\n", __func__,
            vs->ioc, mn[vs->share_mode], mn[mode]);
77 78
#endif

G
Gerd Hoffmann 已提交
79 80 81 82 83 84 85 86
    switch (vs->share_mode) {
    case VNC_SHARE_MODE_CONNECTING:
        vs->vd->num_connecting--;
        break;
    case VNC_SHARE_MODE_SHARED:
        vs->vd->num_shared--;
        break;
    case VNC_SHARE_MODE_EXCLUSIVE:
87
        vs->vd->num_exclusive--;
G
Gerd Hoffmann 已提交
88 89 90
        break;
    default:
        break;
91
    }
G
Gerd Hoffmann 已提交
92

93
    vs->share_mode = mode;
G
Gerd Hoffmann 已提交
94 95 96 97 98 99 100 101 102

    switch (vs->share_mode) {
    case VNC_SHARE_MODE_CONNECTING:
        vs->vd->num_connecting++;
        break;
    case VNC_SHARE_MODE_SHARED:
        vs->vd->num_shared++;
        break;
    case VNC_SHARE_MODE_EXCLUSIVE:
103
        vs->vd->num_exclusive++;
G
Gerd Hoffmann 已提交
104 105 106
        break;
    default:
        break;
107 108 109
    }
}

110

111
static void vnc_init_basic_info(SocketAddress *addr,
112 113
                                VncBasicInfo *info,
                                Error **errp)
114
{
115
    switch (addr->type) {
116 117 118 119
    case SOCKET_ADDRESS_TYPE_INET:
        info->host = g_strdup(addr->u.inet.host);
        info->service = g_strdup(addr->u.inet.port);
        if (addr->u.inet.ipv6) {
120 121 122 123 124
            info->family = NETWORK_ADDRESS_FAMILY_IPV6;
        } else {
            info->family = NETWORK_ADDRESS_FAMILY_IPV4;
        }
        break;
125

126
    case SOCKET_ADDRESS_TYPE_UNIX:
127
        info->host = g_strdup("");
128
        info->service = g_strdup(addr->u.q_unix.path);
129 130 131
        info->family = NETWORK_ADDRESS_FAMILY_UNIX;
        break;

132 133
    case SOCKET_ADDRESS_TYPE_VSOCK:
    case SOCKET_ADDRESS_TYPE_FD:
134
        error_setg(errp, "Unsupported socket address type %s",
135
                   SocketAddressType_str(addr->type));
136
        break;
137 138
    default:
        abort();
139 140
    }

141
    return;
142 143
}

144 145
static void vnc_init_basic_info_from_server_addr(QIOChannelSocket *ioc,
                                                 VncBasicInfo *info,
146
                                                 Error **errp)
147
{
148
    SocketAddress *addr = NULL;
149

150 151 152 153 154
    if (!ioc) {
        error_setg(errp, "No listener socket available");
        return;
    }

155 156
    addr = qio_channel_socket_get_local_address(ioc, errp);
    if (!addr) {
157
        return;
158 159
    }

160
    vnc_init_basic_info(addr, info, errp);
161
    qapi_free_SocketAddress(addr);
162 163
}

164 165
static void vnc_init_basic_info_from_remote_addr(QIOChannelSocket *ioc,
                                                 VncBasicInfo *info,
166
                                                 Error **errp)
167
{
168
    SocketAddress *addr = NULL;
169

170 171
    addr = qio_channel_socket_get_remote_address(ioc, errp);
    if (!addr) {
172
        return;
173 174
    }

175
    vnc_init_basic_info(addr, info, errp);
176
    qapi_free_SocketAddress(addr);
177 178
}

179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
static const char *vnc_auth_name(VncDisplay *vd) {
    switch (vd->auth) {
    case VNC_AUTH_INVALID:
        return "invalid";
    case VNC_AUTH_NONE:
        return "none";
    case VNC_AUTH_VNC:
        return "vnc";
    case VNC_AUTH_RA2:
        return "ra2";
    case VNC_AUTH_RA2NE:
        return "ra2ne";
    case VNC_AUTH_TIGHT:
        return "tight";
    case VNC_AUTH_ULTRA:
        return "ultra";
    case VNC_AUTH_TLS:
        return "tls";
    case VNC_AUTH_VENCRYPT:
        switch (vd->subauth) {
        case VNC_AUTH_VENCRYPT_PLAIN:
            return "vencrypt+plain";
        case VNC_AUTH_VENCRYPT_TLSNONE:
            return "vencrypt+tls+none";
        case VNC_AUTH_VENCRYPT_TLSVNC:
            return "vencrypt+tls+vnc";
        case VNC_AUTH_VENCRYPT_TLSPLAIN:
            return "vencrypt+tls+plain";
        case VNC_AUTH_VENCRYPT_X509NONE:
            return "vencrypt+x509+none";
        case VNC_AUTH_VENCRYPT_X509VNC:
            return "vencrypt+x509+vnc";
        case VNC_AUTH_VENCRYPT_X509PLAIN:
            return "vencrypt+x509+plain";
213 214 215 216
        case VNC_AUTH_VENCRYPT_TLSSASL:
            return "vencrypt+tls+sasl";
        case VNC_AUTH_VENCRYPT_X509SASL:
            return "vencrypt+x509+sasl";
217 218 219
        default:
            return "vencrypt";
        }
220
    case VNC_AUTH_SASL:
221
        return "sasl";
222 223 224 225
    }
    return "unknown";
}

G
Gerd Hoffmann 已提交
226
static VncServerInfo *vnc_server_info_get(VncDisplay *vd)
L
Luiz Capitulino 已提交
227
{
W
Wenchao Xia 已提交
228
    VncServerInfo *info;
229
    Error *err = NULL;
L
Luiz Capitulino 已提交
230

231
    if (!vd->listener || !vd->listener->nsioc) {
232 233 234
        return NULL;
    }

235
    info = g_malloc0(sizeof(*info));
236
    vnc_init_basic_info_from_server_addr(vd->listener->sioc[0],
E
Eric Blake 已提交
237
                                         qapi_VncServerInfo_base(info), &err);
W
Wenchao Xia 已提交
238
    info->has_auth = true;
G
Gerd Hoffmann 已提交
239
    info->auth = g_strdup(vnc_auth_name(vd));
240 241 242 243 244
    if (err) {
        qapi_free_VncServerInfo(info);
        info = NULL;
        error_free(err);
    }
W
Wenchao Xia 已提交
245
    return info;
L
Luiz Capitulino 已提交
246 247
}

248
static void vnc_client_cache_auth(VncState *client)
249
{
250 251
    if (!client->info) {
        return;
252
    }
253

254 255 256 257 258
    if (client->tls) {
        client->info->x509_dname =
            qcrypto_tls_session_get_peer_name(client->tls);
        client->info->has_x509_dname =
            client->info->x509_dname != NULL;
259
    }
260 261
#ifdef CONFIG_VNC_SASL
    if (client->sasl.conn &&
262
        client->sasl.username) {
W
Wenchao Xia 已提交
263 264
        client->info->has_sasl_username = true;
        client->info->sasl_username = g_strdup(client->sasl.username);
265
    }
266
#endif
267
}
268

269 270
static void vnc_client_cache_addr(VncState *client)
{
271 272 273
    Error *err = NULL;

    client->info = g_malloc0(sizeof(*client->info));
274
    vnc_init_basic_info_from_remote_addr(client->sioc,
E
Eric Blake 已提交
275
                                         qapi_VncClientInfo_base(client->info),
276 277 278 279 280
                                         &err);
    if (err) {
        qapi_free_VncClientInfo(client->info);
        client->info = NULL;
        error_free(err);
281
    }
282 283
}

W
Wenchao Xia 已提交
284
static void vnc_qmp_event(VncState *vs, QAPIEvent event)
285
{
W
Wenchao Xia 已提交
286
    VncServerInfo *si;
287 288 289 290 291

    if (!vs->info) {
        return;
    }

G
Gerd Hoffmann 已提交
292
    si = vnc_server_info_get(vs->vd);
W
Wenchao Xia 已提交
293
    if (!si) {
294 295 296
        return;
    }

W
Wenchao Xia 已提交
297 298
    switch (event) {
    case QAPI_EVENT_VNC_CONNECTED:
299
        qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info));
W
Wenchao Xia 已提交
300 301
        break;
    case QAPI_EVENT_VNC_INITIALIZED:
302
        qapi_event_send_vnc_initialized(si, vs->info);
W
Wenchao Xia 已提交
303 304
        break;
    case QAPI_EVENT_VNC_DISCONNECTED:
305
        qapi_event_send_vnc_disconnected(si, vs->info);
W
Wenchao Xia 已提交
306 307 308 309
        break;
    default:
        break;
    }
310

W
Wenchao Xia 已提交
311
    qapi_free_VncServerInfo(si);
312 313
}

L
Luiz Capitulino 已提交
314
static VncClientInfo *qmp_query_vnc_client(const VncState *client)
B
bellard 已提交
315
{
L
Luiz Capitulino 已提交
316
    VncClientInfo *info;
317
    Error *err = NULL;
L
Luiz Capitulino 已提交
318

319
    info = g_malloc0(sizeof(*info));
L
Luiz Capitulino 已提交
320

321 322 323 324 325 326
    vnc_init_basic_info_from_remote_addr(client->sioc,
                                         qapi_VncClientInfo_base(info),
                                         &err);
    if (err) {
        error_free(err);
        qapi_free_VncClientInfo(info);
L
Luiz Capitulino 已提交
327 328
        return NULL;
    }
329

E
Eric Blake 已提交
330
    info->websocket = client->websocket;
331

332 333 334
    if (client->tls) {
        info->x509_dname = qcrypto_tls_session_get_peer_name(client->tls);
        info->has_x509_dname = info->x509_dname != NULL;
L
Luiz Capitulino 已提交
335
    }
336
#ifdef CONFIG_VNC_SASL
L
Luiz Capitulino 已提交
337 338 339
    if (client->sasl.conn && client->sasl.username) {
        info->has_sasl_username = true;
        info->sasl_username = g_strdup(client->sasl.username);
340
    }
L
Luiz Capitulino 已提交
341
#endif
342

L
Luiz Capitulino 已提交
343
    return info;
344
}
345

G
Gerd Hoffmann 已提交
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
static VncDisplay *vnc_display_find(const char *id)
{
    VncDisplay *vd;

    if (id == NULL) {
        return QTAILQ_FIRST(&vnc_displays);
    }
    QTAILQ_FOREACH(vd, &vnc_displays, next) {
        if (strcmp(id, vd->id) == 0) {
            return vd;
        }
    }
    return NULL;
}

361 362 363 364 365 366 367 368 369 370 371 372 373 374
static VncClientInfoList *qmp_query_client_list(VncDisplay *vd)
{
    VncClientInfoList *cinfo, *prev = NULL;
    VncState *client;

    QTAILQ_FOREACH(client, &vd->clients, next) {
        cinfo = g_new0(VncClientInfoList, 1);
        cinfo->value = qmp_query_vnc_client(client);
        cinfo->next = prev;
        prev = cinfo;
    }
    return prev;
}

L
Luiz Capitulino 已提交
375
VncInfo *qmp_query_vnc(Error **errp)
376
{
L
Luiz Capitulino 已提交
377
    VncInfo *info = g_malloc0(sizeof(*info));
G
Gerd Hoffmann 已提交
378
    VncDisplay *vd = vnc_display_find(NULL);
379
    SocketAddress *addr = NULL;
L
Luiz Capitulino 已提交
380

381
    if (vd == NULL || !vd->listener || !vd->listener->nsioc) {
L
Luiz Capitulino 已提交
382
        info->enabled = false;
383
    } else {
L
Luiz Capitulino 已提交
384 385 386 387
        info->enabled = true;

        /* for compatibility with the original command */
        info->has_clients = true;
388
        info->clients = qmp_query_client_list(vd);
389

390 391
        addr = qio_channel_socket_get_local_address(vd->listener->sioc[0],
                                                    errp);
392
        if (!addr) {
L
Luiz Capitulino 已提交
393 394
            goto out_error;
        }
395

396
        switch (addr->type) {
397 398 399 400
        case SOCKET_ADDRESS_TYPE_INET:
            info->host = g_strdup(addr->u.inet.host);
            info->service = g_strdup(addr->u.inet.port);
            if (addr->u.inet.ipv6) {
401 402 403 404 405 406
                info->family = NETWORK_ADDRESS_FAMILY_IPV6;
            } else {
                info->family = NETWORK_ADDRESS_FAMILY_IPV4;
            }
            break;

407
        case SOCKET_ADDRESS_TYPE_UNIX:
408
            info->host = g_strdup("");
409
            info->service = g_strdup(addr->u.q_unix.path);
410 411 412
            info->family = NETWORK_ADDRESS_FAMILY_UNIX;
            break;

413 414
        case SOCKET_ADDRESS_TYPE_VSOCK:
        case SOCKET_ADDRESS_TYPE_FD:
415
            error_setg(errp, "Unsupported socket address type %s",
416
                       SocketAddressType_str(addr->type));
L
Luiz Capitulino 已提交
417
            goto out_error;
418 419
        default:
            abort();
420
        }
L
Luiz Capitulino 已提交
421 422 423 424 425 426

        info->has_host = true;
        info->has_service = true;
        info->has_family = true;

        info->has_auth = true;
G
Gerd Hoffmann 已提交
427
        info->auth = g_strdup(vnc_auth_name(vd));
B
bellard 已提交
428
    }
L
Luiz Capitulino 已提交
429

430
    qapi_free_SocketAddress(addr);
L
Luiz Capitulino 已提交
431 432 433
    return info;

out_error:
434
    qapi_free_SocketAddress(addr);
L
Luiz Capitulino 已提交
435 436
    qapi_free_VncInfo(info);
    return NULL;
B
bellard 已提交
437 438
}

439 440 441 442 443 444 445 446 447 448 449

static void qmp_query_auth(int auth, int subauth,
                           VncPrimaryAuth *qmp_auth,
                           VncVencryptSubAuth *qmp_vencrypt,
                           bool *qmp_has_vencrypt);

static VncServerInfo2List *qmp_query_server_entry(QIOChannelSocket *ioc,
                                                  bool websocket,
                                                  int auth,
                                                  int subauth,
                                                  VncServerInfo2List *prev)
450
{
451 452
    VncServerInfo2List *list;
    VncServerInfo2 *info;
453
    Error *err = NULL;
454
    SocketAddress *addr;
455 456 457 458

    addr = qio_channel_socket_get_local_address(ioc, &err);
    if (!addr) {
        error_free(err);
459 460 461
        return prev;
    }

462 463
    info = g_new0(VncServerInfo2, 1);
    vnc_init_basic_info(addr, qapi_VncServerInfo2_base(info), &err);
464
    qapi_free_SocketAddress(addr);
465
    if (err) {
466
        qapi_free_VncServerInfo2(info);
467 468 469
        error_free(err);
        return prev;
    }
G
Gerd Hoffmann 已提交
470
    info->websocket = websocket;
471

472 473 474 475
    qmp_query_auth(auth, subauth, &info->auth,
                   &info->vencrypt, &info->has_vencrypt);

    list = g_new0(VncServerInfo2List, 1);
476 477 478 479 480
    list->value = info;
    list->next = prev;
    return list;
}

481 482 483 484
static void qmp_query_auth(int auth, int subauth,
                           VncPrimaryAuth *qmp_auth,
                           VncVencryptSubAuth *qmp_vencrypt,
                           bool *qmp_has_vencrypt)
485
{
486
    switch (auth) {
487
    case VNC_AUTH_VNC:
488
        *qmp_auth = VNC_PRIMARY_AUTH_VNC;
489 490
        break;
    case VNC_AUTH_RA2:
491
        *qmp_auth = VNC_PRIMARY_AUTH_RA2;
492 493
        break;
    case VNC_AUTH_RA2NE:
494
        *qmp_auth = VNC_PRIMARY_AUTH_RA2NE;
495 496
        break;
    case VNC_AUTH_TIGHT:
497
        *qmp_auth = VNC_PRIMARY_AUTH_TIGHT;
498 499
        break;
    case VNC_AUTH_ULTRA:
500
        *qmp_auth = VNC_PRIMARY_AUTH_ULTRA;
501 502
        break;
    case VNC_AUTH_TLS:
503
        *qmp_auth = VNC_PRIMARY_AUTH_TLS;
504 505
        break;
    case VNC_AUTH_VENCRYPT:
506 507 508
        *qmp_auth = VNC_PRIMARY_AUTH_VENCRYPT;
        *qmp_has_vencrypt = true;
        switch (subauth) {
509
        case VNC_AUTH_VENCRYPT_PLAIN:
510
            *qmp_vencrypt = VNC_VENCRYPT_SUB_AUTH_PLAIN;
511 512
            break;
        case VNC_AUTH_VENCRYPT_TLSNONE:
513
            *qmp_vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_NONE;
514 515
            break;
        case VNC_AUTH_VENCRYPT_TLSVNC:
516
            *qmp_vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_VNC;
517 518
            break;
        case VNC_AUTH_VENCRYPT_TLSPLAIN:
519
            *qmp_vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_PLAIN;
520 521
            break;
        case VNC_AUTH_VENCRYPT_X509NONE:
522
            *qmp_vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_NONE;
523 524
            break;
        case VNC_AUTH_VENCRYPT_X509VNC:
525
            *qmp_vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_VNC;
526 527
            break;
        case VNC_AUTH_VENCRYPT_X509PLAIN:
528
            *qmp_vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_PLAIN;
529 530
            break;
        case VNC_AUTH_VENCRYPT_TLSSASL:
531
            *qmp_vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_SASL;
532 533
            break;
        case VNC_AUTH_VENCRYPT_X509SASL:
534
            *qmp_vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_SASL;
535 536
            break;
        default:
537
            *qmp_has_vencrypt = false;
538 539 540 541
            break;
        }
        break;
    case VNC_AUTH_SASL:
542
        *qmp_auth = VNC_PRIMARY_AUTH_SASL;
543 544 545
        break;
    case VNC_AUTH_NONE:
    default:
546
        *qmp_auth = VNC_PRIMARY_AUTH_NONE;
547 548 549 550 551 552 553 554 555 556
        break;
    }
}

VncInfo2List *qmp_query_vnc_servers(Error **errp)
{
    VncInfo2List *item, *prev = NULL;
    VncInfo2 *info;
    VncDisplay *vd;
    DeviceState *dev;
557
    size_t i;
558 559 560 561 562

    QTAILQ_FOREACH(vd, &vnc_displays, next) {
        info = g_new0(VncInfo2, 1);
        info->id = g_strdup(vd->id);
        info->clients = qmp_query_client_list(vd);
563 564
        qmp_query_auth(vd->auth, vd->subauth, &info->auth,
                       &info->vencrypt, &info->has_vencrypt);
565 566 567 568 569 570
        if (vd->dcl.con) {
            dev = DEVICE(object_property_get_link(OBJECT(vd->dcl.con),
                                                  "device", NULL));
            info->has_display = true;
            info->display = g_strdup(dev->id);
        }
571
        for (i = 0; vd->listener != NULL && i < vd->listener->nsioc; i++) {
572
            info->server = qmp_query_server_entry(
573 574
                vd->listener->sioc[i], false, vd->auth, vd->subauth,
                info->server);
575
        }
576
        for (i = 0; vd->wslistener != NULL && i < vd->wslistener->nsioc; i++) {
577
            info->server = qmp_query_server_entry(
578
                vd->wslistener->sioc[i], true, vd->ws_auth,
579
                vd->ws_subauth, info->server);
580 581 582 583 584 585 586 587 588 589
        }

        item = g_new0(VncInfo2List, 1);
        item->value = info;
        item->next = prev;
        prev = item;
    }
    return prev;
}

B
bellard 已提交
590 591 592 593 594 595 596
/* TODO
   1) Get the queue working for IO.
   2) there is some weirdness when using the -S option (the screen is grey
      and not totally invalidated
   3) resolutions > 1024
*/

597
static int vnc_update_client(VncState *vs, int has_dirty);
598
static void vnc_disconnect_start(VncState *vs);
B
bellard 已提交
599

600
static void vnc_colordepth(VncState *vs);
S
Stefano Stabellini 已提交
601 602 603
static void framebuffer_update_request(VncState *vs, int incremental,
                                       int x_position, int y_position,
                                       int w, int h);
G
Gerd Hoffmann 已提交
604
static void vnc_refresh(DisplayChangeListener *dcl);
S
Stefano Stabellini 已提交
605
static int vnc_refresh_server_surface(VncDisplay *vd);
606

607 608 609 610 611 612 613 614 615 616 617
static int vnc_width(VncDisplay *vd)
{
    return MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
                                       VNC_DIRTY_PIXELS_PER_BIT));
}

static int vnc_height(VncDisplay *vd)
{
    return MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
}

618 619
static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
                               VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT),
620 621 622 623 624 625
                               VncDisplay *vd,
                               int x, int y, int w, int h)
{
    int width = vnc_width(vd);
    int height = vnc_height(vd);

626 627
    /* this is needed this to ensure we updated all affected
     * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
628 629
    w += (x % VNC_DIRTY_PIXELS_PER_BIT);
    x -= (x % VNC_DIRTY_PIXELS_PER_BIT);
630

631 632 633
    x = MIN(x, width);
    y = MIN(y, height);
    w = MIN(x + w, width) - x;
634
    h = MIN(y + h, height);
635

636
    for (; y < h; y++) {
637
        bitmap_set(dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
638
                   DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
639
    }
B
bellard 已提交
640 641
}

642 643 644 645 646 647
static void vnc_dpy_update(DisplayChangeListener *dcl,
                           int x, int y, int w, int h)
{
    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
    struct VncSurface *s = &vd->guest;

648
    vnc_set_area_dirty(s->dirty, vd, x, y, w, h);
649 650
}

651 652
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
                            int32_t encoding)
B
bellard 已提交
653 654 655 656 657 658 659 660 661
{
    vnc_write_u16(vs, x);
    vnc_write_u16(vs, y);
    vnc_write_u16(vs, w);
    vnc_write_u16(vs, h);

    vnc_write_s32(vs, encoding);
}

T
Tim Hardeck 已提交
662

663 664
static void vnc_desktop_resize(VncState *vs)
{
665
    if (vs->ioc == NULL || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
666 667
        return;
    }
668 669
    if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
        vs->client_height == pixman_image_get_height(vs->vd->server)) {
670 671
        return;
    }
672 673 674 675 676

    assert(pixman_image_get_width(vs->vd->server) < 65536 &&
           pixman_image_get_width(vs->vd->server) >= 0);
    assert(pixman_image_get_height(vs->vd->server) < 65536 &&
           pixman_image_get_height(vs->vd->server) >= 0);
677 678
    vs->client_width = pixman_image_get_width(vs->vd->server);
    vs->client_height = pixman_image_get_height(vs->vd->server);
C
Corentin Chary 已提交
679
    vnc_lock_output(vs);
680 681 682
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
    vnc_write_u8(vs, 0);
    vnc_write_u16(vs, 1); /* number of rects */
683
    vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
684
                           VNC_ENCODING_DESKTOPRESIZE);
C
Corentin Chary 已提交
685
    vnc_unlock_output(vs);
686 687 688
    vnc_flush(vs);
}

C
Corentin Chary 已提交
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
static void vnc_abort_display_jobs(VncDisplay *vd)
{
    VncState *vs;

    QTAILQ_FOREACH(vs, &vd->clients, next) {
        vnc_lock_output(vs);
        vs->abort = true;
        vnc_unlock_output(vs);
    }
    QTAILQ_FOREACH(vs, &vd->clients, next) {
        vnc_jobs_join(vs);
    }
    QTAILQ_FOREACH(vs, &vd->clients, next) {
        vnc_lock_output(vs);
        vs->abort = false;
        vnc_unlock_output(vs);
    }
}

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
int vnc_server_fb_stride(VncDisplay *vd)
{
    return pixman_image_get_stride(vd->server);
}

void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
{
    uint8_t *ptr;

    ptr  = (uint8_t *)pixman_image_get_data(vd->server);
    ptr += y * vnc_server_fb_stride(vd);
    ptr += x * VNC_SERVER_FB_BYTES;
    return ptr;
}

723 724
static void vnc_update_server_surface(VncDisplay *vd)
{
725 726
    int width, height;

727 728 729
    qemu_pixman_image_unref(vd->server);
    vd->server = NULL;

730 731 732 733
    if (QTAILQ_EMPTY(&vd->clients)) {
        return;
    }

734 735
    width = vnc_width(vd);
    height = vnc_height(vd);
736
    vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
737
                                          width, height,
738
                                          NULL, 0);
739 740 741 742

    memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty));
    vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0,
                       width, height);
743 744
}

745 746
static void vnc_dpy_switch(DisplayChangeListener *dcl,
                           DisplaySurface *surface)
B
bellard 已提交
747
{
748 749 750
    static const char placeholder_msg[] =
        "Display output is not active.";
    static DisplaySurface *placeholder;
751
    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
752
    VncState *vs;
S
Stefano Stabellini 已提交
753

754 755 756 757 758 759 760
    if (surface == NULL) {
        if (placeholder == NULL) {
            placeholder = qemu_create_message_surface(640, 480, placeholder_msg);
        }
        surface = placeholder;
    }

C
Corentin Chary 已提交
761
    vnc_abort_display_jobs(vd);
762
    vd->ds = surface;
C
Corentin Chary 已提交
763

S
Stefano Stabellini 已提交
764
    /* server surface */
765
    vnc_update_server_surface(vd);
B
bellard 已提交
766

767
    /* guest surface */
768
    qemu_pixman_image_unref(vd->guest.fb);
G
Gerd Hoffmann 已提交
769 770
    vd->guest.fb = pixman_image_ref(surface->image);
    vd->guest.format = surface->format;
B
bellard 已提交
771

772
    QTAILQ_FOREACH(vs, &vd->clients, next) {
S
Stefano Stabellini 已提交
773
        vnc_colordepth(vs);
774
        vnc_desktop_resize(vs);
G
Gerd Hoffmann 已提交
775 776 777
        if (vs->vd->cursor) {
            vnc_cursor_define(vs);
        }
778
        memset(vs->dirty, 0x00, sizeof(vs->dirty));
779
        vnc_set_area_dirty(vs->dirty, vd, 0, 0,
780 781
                           vnc_width(vd),
                           vnc_height(vd));
782
        vnc_update_throttle_offset(vs);
783 784 785
    }
}

B
bellard 已提交
786
/* fastest code */
787
static void vnc_write_pixels_copy(VncState *vs,
G
Gerd Hoffmann 已提交
788
                                  void *pixels, int size)
B
bellard 已提交
789 790 791 792 793
{
    vnc_write(vs, pixels, size);
}

/* slowest but generic code. */
794
void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
B
bellard 已提交
795
{
796
    uint8_t r, g, b;
S
Stefano Stabellini 已提交
797

798 799 800 801 802 803 804 805 806 807 808
#if VNC_SERVER_FB_FORMAT == PIXMAN_FORMAT(32, PIXMAN_TYPE_ARGB, 0, 8, 8, 8)
    r = (((v & 0x00ff0000) >> 16) << vs->client_pf.rbits) >> 8;
    g = (((v & 0x0000ff00) >>  8) << vs->client_pf.gbits) >> 8;
    b = (((v & 0x000000ff) >>  0) << vs->client_pf.bbits) >> 8;
#else
# error need some bits here if you change VNC_SERVER_FB_FORMAT
#endif
    v = (r << vs->client_pf.rshift) |
        (g << vs->client_pf.gshift) |
        (b << vs->client_pf.bshift);
    switch (vs->client_pf.bytes_per_pixel) {
B
bellard 已提交
809 810 811 812
    case 1:
        buf[0] = v;
        break;
    case 2:
813
        if (vs->client_be) {
B
bellard 已提交
814 815 816 817 818 819 820 821 822
            buf[0] = v >> 8;
            buf[1] = v;
        } else {
            buf[1] = v >> 8;
            buf[0] = v;
        }
        break;
    default:
    case 4:
823
        if (vs->client_be) {
B
bellard 已提交
824 825 826 827 828 829 830 831 832 833 834 835 836 837
            buf[0] = v >> 24;
            buf[1] = v >> 16;
            buf[2] = v >> 8;
            buf[3] = v;
        } else {
            buf[3] = v >> 24;
            buf[2] = v >> 16;
            buf[1] = v >> 8;
            buf[0] = v;
        }
        break;
    }
}

838
static void vnc_write_pixels_generic(VncState *vs,
G
Gerd Hoffmann 已提交
839
                                     void *pixels1, int size)
B
bellard 已提交
840 841 842
{
    uint8_t buf[4];

843
    if (VNC_SERVER_FB_BYTES == 4) {
844 845 846
        uint32_t *pixels = pixels1;
        int n, i;
        n = size >> 2;
847
        for (i = 0; i < n; i++) {
848
            vnc_convert_pixel(vs, buf, pixels[i]);
849
            vnc_write(vs, buf, vs->client_pf.bytes_per_pixel);
850
        }
B
bellard 已提交
851 852 853
    }
}

854
int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
B
bellard 已提交
855 856
{
    int i;
T
ths 已提交
857
    uint8_t *row;
S
Stefano Stabellini 已提交
858
    VncDisplay *vd = vs->vd;
B
bellard 已提交
859

860
    row = vnc_server_fb_ptr(vd, x, y);
B
bellard 已提交
861
    for (i = 0; i < h; i++) {
862 863
        vs->write_pixels(vs, row, w * VNC_SERVER_FB_BYTES);
        row += vnc_server_fb_stride(vd);
B
bellard 已提交
864
    }
865
    return 1;
B
bellard 已提交
866 867
}

C
Corentin Chary 已提交
868
int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
B
bellard 已提交
869
{
870
    int n = 0;
871 872
    bool encode_raw = false;
    size_t saved_offs = vs->output.offset;
873

874
    switch(vs->vnc_encoding) {
875
        case VNC_ENCODING_ZLIB:
876
            n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
877 878 879
            break;
        case VNC_ENCODING_HEXTILE:
            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
880
            n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
881
            break;
C
Corentin Chary 已提交
882 883 884
        case VNC_ENCODING_TIGHT:
            n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
            break;
C
Corentin Chary 已提交
885 886 887
        case VNC_ENCODING_TIGHT_PNG:
            n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
            break;
888 889 890 891 892 893
        case VNC_ENCODING_ZRLE:
            n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
            break;
        case VNC_ENCODING_ZYWRLE:
            n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
            break;
894
        default:
895
            encode_raw = true;
896
            break;
897
    }
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912

    /* If the client has the same pixel format as our internal buffer and
     * a RAW encoding would need less space fall back to RAW encoding to
     * save bandwidth and processing power in the client. */
    if (!encode_raw && vs->write_pixels == vnc_write_pixels_copy &&
        12 + h * w * VNC_SERVER_FB_BYTES <= (vs->output.offset - saved_offs)) {
        vs->output.offset = saved_offs;
        encode_raw = true;
    }

    if (encode_raw) {
        vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
        n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
    }

913
    return n;
B
bellard 已提交
914 915
}

916 917
static void vnc_mouse_set(DisplayChangeListener *dcl,
                          int x, int y, int visible)
G
Gerd Hoffmann 已提交
918 919 920 921 922 923 924 925 926 927
{
    /* can we ask the client(s) to move the pointer ??? */
}

static int vnc_cursor_define(VncState *vs)
{
    QEMUCursor *c = vs->vd->cursor;
    int isize;

    if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
928
        vnc_lock_output(vs);
G
Gerd Hoffmann 已提交
929 930 931 932 933
        vnc_write_u8(vs,  VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
        vnc_write_u8(vs,  0);  /*  padding     */
        vnc_write_u16(vs, 1);  /*  # of rects  */
        vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
                               VNC_ENCODING_RICH_CURSOR);
934 935
        isize = c->width * c->height * vs->client_pf.bytes_per_pixel;
        vnc_write_pixels_generic(vs, c->data, isize);
G
Gerd Hoffmann 已提交
936
        vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
937
        vnc_unlock_output(vs);
G
Gerd Hoffmann 已提交
938 939 940 941 942
        return 0;
    }
    return -1;
}

943 944
static void vnc_dpy_cursor_define(DisplayChangeListener *dcl,
                                  QEMUCursor *c)
G
Gerd Hoffmann 已提交
945
{
G
Gerd Hoffmann 已提交
946
    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
G
Gerd Hoffmann 已提交
947 948 949
    VncState *vs;

    cursor_put(vd->cursor);
950
    g_free(vd->cursor_mask);
G
Gerd Hoffmann 已提交
951 952 953 954

    vd->cursor = c;
    cursor_get(vd->cursor);
    vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
955
    vd->cursor_mask = g_malloc0(vd->cursor_msize);
G
Gerd Hoffmann 已提交
956 957 958 959 960 961 962
    cursor_get_mono_mask(c, 0, vd->cursor_mask);

    QTAILQ_FOREACH(vs, &vd->clients, next) {
        vnc_cursor_define(vs);
    }
}

963
static int find_and_clear_dirty_height(VncState *vs,
964
                                       int y, int last_x, int x, int height)
B
bellard 已提交
965 966 967
{
    int h;

968
    for (h = 1; h < (height - y); h++) {
969
        if (!test_bit(last_x, vs->dirty[y + h])) {
970
            break;
971
        }
972
        bitmap_clear(vs->dirty[y + h], last_x, x - last_x);
B
bellard 已提交
973 974 975 976 977
    }

    return h;
}

978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
/*
 * Figure out how much pending data we should allow in the output
 * buffer before we throttle incremental display updates, and/or
 * drop audio samples.
 *
 * We allow for equiv of 1 full display's worth of FB updates,
 * and 1 second of audio samples. If audio backlog was larger
 * than that the client would already suffering awful audio
 * glitches, so dropping samples is no worse really).
 */
static void vnc_update_throttle_offset(VncState *vs)
{
    size_t offset =
        vs->client_width * vs->client_height * vs->client_pf.bytes_per_pixel;

    if (vs->audio_cap) {
        int bps;
        switch (vs->as.fmt) {
        default:
        case  AUD_FMT_U8:
        case  AUD_FMT_S8:
            bps = 1;
            break;
        case  AUD_FMT_U16:
        case  AUD_FMT_S16:
            bps = 2;
            break;
        case  AUD_FMT_U32:
        case  AUD_FMT_S32:
            bps = 4;
            break;
        }
1010
        offset += vs->as.freq * bps * vs->as.nchannels;
1011 1012 1013 1014 1015 1016 1017 1018
    }

    /* Put a floor of 1MB on offset, so that if we have a large pending
     * buffer and the display is resized to a small size & back again
     * we don't suddenly apply a tiny send limit
     */
    offset = MAX(offset, 1024 * 1024);

1019 1020 1021 1022 1023 1024
    if (vs->throttle_output_offset != offset) {
        trace_vnc_client_throttle_threshold(
            vs, vs->ioc, vs->throttle_output_offset, offset, vs->client_width,
            vs->client_height, vs->client_pf.bytes_per_pixel, vs->audio_cap);
    }

1025 1026 1027
    vs->throttle_output_offset = offset;
}

1028 1029 1030 1031 1032 1033
static bool vnc_should_update(VncState *vs)
{
    switch (vs->update) {
    case VNC_STATE_UPDATE_NONE:
        break;
    case VNC_STATE_UPDATE_INCREMENTAL:
1034
        /* Only allow incremental updates if the pending send queue
1035 1036
         * is less than the permitted threshold, and the job worker
         * is completely idle.
1037
         */
1038 1039
        if (vs->output.offset < vs->throttle_output_offset &&
            vs->job_update == VNC_STATE_UPDATE_NONE) {
1040 1041
            return true;
        }
1042 1043
        trace_vnc_client_throttle_incremental(
            vs, vs->ioc, vs->job_update, vs->output.offset);
1044 1045
        break;
    case VNC_STATE_UPDATE_FORCE:
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
        /* Only allow forced updates if the pending send queue
         * does not contain a previous forced update, and the
         * job worker is completely idle.
         *
         * Note this means we'll queue a forced update, even if
         * the output buffer size is otherwise over the throttle
         * output limit.
         */
        if (vs->force_update_offset == 0 &&
            vs->job_update == VNC_STATE_UPDATE_NONE) {
            return true;
        }
1058 1059
        trace_vnc_client_throttle_forced(
            vs, vs->ioc, vs->job_update, vs->force_update_offset);
1060
        break;
1061 1062 1063 1064
    }
    return false;
}

1065
static int vnc_update_client(VncState *vs, int has_dirty)
B
bellard 已提交
1066
{
1067 1068 1069 1070 1071 1072
    VncDisplay *vd = vs->vd;
    VncJob *job;
    int y;
    int height, width;
    int n = 0;

1073 1074 1075 1076 1077
    if (vs->disconnecting) {
        vnc_disconnect_finish(vs);
        return 0;
    }

G
Gerd Hoffmann 已提交
1078
    vs->has_dirty += has_dirty;
1079
    if (!vnc_should_update(vs)) {
1080 1081 1082
        return 0;
    }

1083
    if (!vs->has_dirty && vs->update != VNC_STATE_UPDATE_FORCE) {
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
        return 0;
    }

    /*
     * Send screen updates to the vnc client using the server
     * surface and server dirty map.  guest surface updates
     * happening in parallel don't disturb us, the next pass will
     * send them to the client.
     */
    job = vnc_job_new(vs);

    height = pixman_image_get_height(vd->server);
    width = pixman_image_get_width(vd->server);

    y = 0;
    for (;;) {
        int x, h;
        unsigned long x2;
        unsigned long offset = find_next_bit((unsigned long *) &vs->dirty,
                                             height * VNC_DIRTY_BPL(vs),
                                             y * VNC_DIRTY_BPL(vs));
        if (offset == height * VNC_DIRTY_BPL(vs)) {
            /* no more dirty bits */
            break;
        }
        y = offset / VNC_DIRTY_BPL(vs);
        x = offset % VNC_DIRTY_BPL(vs);
        x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y],
                                VNC_DIRTY_BPL(vs), x);
        bitmap_clear(vs->dirty[y], x, x2 - x);
        h = find_and_clear_dirty_height(vs, y, x, x2, height);
        x2 = MIN(x2, width / VNC_DIRTY_PIXELS_PER_BIT);
        if (x2 > x) {
            n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y,
                                  (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h);
        }
        if (!x && x2 == width / VNC_DIRTY_PIXELS_PER_BIT) {
            y += h;
            if (y == height) {
1123
                break;
1124 1125
            }
        }
B
bellard 已提交
1126 1127
    }

1128
    vs->job_update = vs->update;
1129
    vs->update = VNC_STATE_UPDATE_NONE;
1130
    vnc_job_push(job);
1131 1132
    vs->has_dirty = 0;
    return n;
B
bellard 已提交
1133 1134
}

M
malc 已提交
1135 1136 1137 1138 1139
/* audio */
static void audio_capture_notify(void *opaque, audcnotification_e cmd)
{
    VncState *vs = opaque;

1140
    assert(vs->magic == VNC_MAGIC);
M
malc 已提交
1141 1142
    switch (cmd) {
    case AUD_CNOTIFY_DISABLE:
C
Corentin Chary 已提交
1143
        vnc_lock_output(vs);
1144 1145 1146
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
C
Corentin Chary 已提交
1147
        vnc_unlock_output(vs);
M
malc 已提交
1148 1149 1150 1151
        vnc_flush(vs);
        break;

    case AUD_CNOTIFY_ENABLE:
C
Corentin Chary 已提交
1152
        vnc_lock_output(vs);
1153 1154 1155
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
C
Corentin Chary 已提交
1156
        vnc_unlock_output(vs);
M
malc 已提交
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
        vnc_flush(vs);
        break;
    }
}

static void audio_capture_destroy(void *opaque)
{
}

static void audio_capture(void *opaque, void *buf, int size)
{
    VncState *vs = opaque;

1170
    assert(vs->magic == VNC_MAGIC);
C
Corentin Chary 已提交
1171
    vnc_lock_output(vs);
1172 1173 1174 1175 1176 1177
    if (vs->output.offset < vs->throttle_output_offset) {
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
        vnc_write_u32(vs, size);
        vnc_write(vs, buf, size);
1178 1179
    } else {
        trace_vnc_client_throttle_audio(vs, vs->ioc, vs->output.offset);
1180
    }
C
Corentin Chary 已提交
1181
    vnc_unlock_output(vs);
M
malc 已提交
1182 1183 1184 1185 1186 1187 1188 1189
    vnc_flush(vs);
}

static void audio_add(VncState *vs)
{
    struct audio_capture_ops ops;

    if (vs->audio_cap) {
C
Cole Robinson 已提交
1190
        error_report("audio already running");
M
malc 已提交
1191 1192 1193 1194 1195 1196 1197
        return;
    }

    ops.notify = audio_capture_notify;
    ops.destroy = audio_capture_destroy;
    ops.capture = audio_capture;

1198
    vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
M
malc 已提交
1199
    if (!vs->audio_cap) {
C
Cole Robinson 已提交
1200
        error_report("Failed to add audio capture");
M
malc 已提交
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
    }
}

static void audio_del(VncState *vs)
{
    if (vs->audio_cap) {
        AUD_del_capture(vs->audio_cap, vs);
        vs->audio_cap = NULL;
    }
}

1212 1213
static void vnc_disconnect_start(VncState *vs)
{
1214
    if (vs->disconnecting) {
1215
        return;
1216
    }
1217
    trace_vnc_client_disconnect_start(vs, vs->ioc);
1218
    vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
1219 1220
    if (vs->ioc_tag) {
        g_source_remove(vs->ioc_tag);
1221
        vs->ioc_tag = 0;
1222 1223 1224
    }
    qio_channel_close(vs->ioc, NULL);
    vs->disconnecting = TRUE;
1225 1226
}

1227
void vnc_disconnect_finish(VncState *vs)
1228
{
1229 1230
    int i;

1231 1232
    trace_vnc_client_disconnect_finish(vs, vs->ioc);

C
Corentin Chary 已提交
1233 1234 1235
    vnc_jobs_join(vs); /* Wait encoding jobs */

    vnc_lock_output(vs);
W
Wenchao Xia 已提交
1236
    vnc_qmp_event(vs, QAPI_EVENT_VNC_DISCONNECTED);
1237

C
Corentin Chary 已提交
1238 1239
    buffer_free(&vs->input);
    buffer_free(&vs->output);
1240

W
Wenchao Xia 已提交
1241
    qapi_free_VncClientInfo(vs->info);
1242

1243
    vnc_zlib_clear(vs);
C
Corentin Chary 已提交
1244
    vnc_tight_clear(vs);
1245
    vnc_zrle_clear(vs);
1246

1247 1248 1249 1250
#ifdef CONFIG_VNC_SASL
    vnc_sasl_client_cleanup(vs);
#endif /* CONFIG_VNC_SASL */
    audio_del(vs);
1251
    vnc_release_modifiers(vs);
1252

1253
    if (vs->mouse_mode_notifier.notify != NULL) {
1254
        qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
1255 1256 1257 1258 1259
    }
    QTAILQ_REMOVE(&vs->vd->clients, vs, next);
    if (QTAILQ_EMPTY(&vs->vd->clients)) {
        /* last client gone */
        vnc_update_server_surface(vs->vd);
1260
    }
1261

C
Corentin Chary 已提交
1262 1263 1264
    vnc_unlock_output(vs);

    qemu_mutex_destroy(&vs->output_mutex);
1265 1266 1267
    if (vs->bh != NULL) {
        qemu_bh_delete(vs->bh);
    }
1268 1269
    buffer_free(&vs->jobs_buffer);

1270
    for (i = 0; i < VNC_STAT_ROWS; ++i) {
1271
        g_free(vs->lossy_rect[i]);
1272
    }
1273
    g_free(vs->lossy_rect);
1274 1275 1276 1277 1278

    object_unref(OBJECT(vs->ioc));
    vs->ioc = NULL;
    object_unref(OBJECT(vs->sioc));
    vs->sioc = NULL;
1279
    vs->magic = 0;
1280
    g_free(vs);
1281
}
1282

1283
size_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp)
B
bellard 已提交
1284
{
1285 1286
    if (ret <= 0) {
        if (ret == 0) {
1287
            trace_vnc_client_eof(vs, vs->ioc);
1288
            vnc_disconnect_start(vs);
1289
        } else if (ret != QIO_CHANNEL_ERR_BLOCK) {
1290 1291 1292
            trace_vnc_client_io_error(vs, vs->ioc,
                                      errp ? error_get_pretty(*errp) :
                                      "Unknown");
1293
            vnc_disconnect_start(vs);
1294
        }
B
bellard 已提交
1295

1296 1297 1298 1299
        if (errp) {
            error_free(*errp);
            *errp = NULL;
        }
1300
        return 0;
B
bellard 已提交
1301 1302 1303 1304
    }
    return ret;
}

1305 1306

void vnc_client_error(VncState *vs)
B
bellard 已提交
1307
{
1308 1309
    VNC_DEBUG("Closing down client sock: protocol error\n");
    vnc_disconnect_start(vs);
B
bellard 已提交
1310 1311
}

1312

1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
/*
 * Called to write a chunk of data to the client socket. The data may
 * be the raw data, or may have already been encoded by SASL.
 * The data will be written either straight onto the socket, or
 * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
 *
 * NB, it is theoretically possible to have 2 layers of encryption,
 * both SASL, and this TLS layer. It is highly unlikely in practice
 * though, since SASL encryption will typically be a no-op if TLS
 * is active
 *
 * Returns the number of bytes written, which may be less than
 * the requested 'datalen' if the socket would block. Returns
1326
 * 0 on I/O error, and disconnects the client socket.
1327
 */
1328
size_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
B
bellard 已提交
1329
{
1330
    Error *err = NULL;
1331
    ssize_t ret;
1332 1333
    ret = qio_channel_write(
        vs->ioc, (const char *)data, datalen, &err);
1334
    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
1335
    return vnc_client_io_error(vs, ret, &err);
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
}


/*
 * Called to write buffered data to the client socket, when not
 * using any SASL SSF encryption layers. Will write as much data
 * as possible without blocking. If all buffered data is written,
 * will switch the FD poll() handler back to read monitoring.
 *
 * Returns the number of bytes written, which may be less than
1346 1347
 * the buffered output data if the socket would block.  Returns
 * 0 on I/O error, and disconnects the client socket.
1348
 */
1349
static size_t vnc_client_write_plain(VncState *vs)
1350
{
1351
    size_t offset;
1352
    size_t ret;
1353 1354

#ifdef CONFIG_VNC_SASL
1355
    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
              vs->output.buffer, vs->output.capacity, vs->output.offset,
              vs->sasl.waitWriteSSF);

    if (vs->sasl.conn &&
        vs->sasl.runSSF &&
        vs->sasl.waitWriteSSF) {
        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
        if (ret)
            vs->sasl.waitWriteSSF -= ret;
    } else
#endif /* CONFIG_VNC_SASL */
        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
B
bellard 已提交
1368
    if (!ret)
1369
        return 0;
B
bellard 已提交
1370

1371
    if (ret >= vs->force_update_offset) {
1372 1373 1374
        if (vs->force_update_offset != 0) {
            trace_vnc_client_unthrottle_forced(vs, vs->ioc);
        }
1375 1376 1377 1378
        vs->force_update_offset = 0;
    } else {
        vs->force_update_offset -= ret;
    }
1379
    offset = vs->output.offset;
T
Tim Hardeck 已提交
1380
    buffer_advance(&vs->output, ret);
1381 1382 1383 1384
    if (offset >= vs->throttle_output_offset &&
        vs->output.offset < vs->throttle_output_offset) {
        trace_vnc_client_unthrottle_incremental(vs, vs->ioc, vs->output.offset);
    }
B
bellard 已提交
1385 1386

    if (vs->output.offset == 0) {
1387 1388 1389 1390 1391
        if (vs->ioc_tag) {
            g_source_remove(vs->ioc_tag);
        }
        vs->ioc_tag = qio_channel_add_watch(
            vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
B
bellard 已提交
1392
    }
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402

    return ret;
}


/*
 * First function called whenever there is data to be written to
 * the client socket. Will delegate actual work according to whether
 * SASL SSF layers are enabled (thus requiring encryption calls)
 */
1403
static void vnc_client_write_locked(VncState *vs)
1404 1405 1406 1407
{
#ifdef CONFIG_VNC_SASL
    if (vs->sasl.conn &&
        vs->sasl.runSSF &&
1408 1409 1410
        !vs->sasl.waitWriteSSF) {
        vnc_client_write_sasl(vs);
    } else
1411
#endif /* CONFIG_VNC_SASL */
1412
    {
1413
        vnc_client_write_plain(vs);
1414
    }
B
bellard 已提交
1415 1416
}

1417
static void vnc_client_write(VncState *vs)
C
Corentin Chary 已提交
1418
{
1419
    assert(vs->magic == VNC_MAGIC);
C
Corentin Chary 已提交
1420
    vnc_lock_output(vs);
1421
    if (vs->output.offset) {
1422 1423 1424 1425 1426 1427 1428
        vnc_client_write_locked(vs);
    } else if (vs->ioc != NULL) {
        if (vs->ioc_tag) {
            g_source_remove(vs->ioc_tag);
        }
        vs->ioc_tag = qio_channel_add_watch(
            vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
C
Corentin Chary 已提交
1429 1430 1431 1432
    }
    vnc_unlock_output(vs);
}

1433
void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
B
bellard 已提交
1434 1435 1436 1437 1438
{
    vs->read_handler = func;
    vs->read_handler_expect = expecting;
}

1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452

/*
 * Called to read a chunk of data from the client socket. The data may
 * be the raw data, or may need to be further decoded by SASL.
 * The data will be read either straight from to the socket, or
 * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
 *
 * NB, it is theoretically possible to have 2 layers of encryption,
 * both SASL, and this TLS layer. It is highly unlikely in practice
 * though, since SASL encryption will typically be a no-op if TLS
 * is active
 *
 * Returns the number of bytes read, which may be less than
 * the requested 'datalen' if the socket would block. Returns
1453
 * 0 on I/O error or EOF, and disconnects the client socket.
1454
 */
1455
size_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
B
bellard 已提交
1456
{
1457
    ssize_t ret;
1458
    Error *err = NULL;
1459 1460
    ret = qio_channel_read(
        vs->ioc, (char *)data, datalen, &err);
1461
    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
1462
    return vnc_client_io_error(vs, ret, &err);
1463
}
B
bellard 已提交
1464

1465 1466 1467 1468 1469 1470

/*
 * Called to read data from the client socket to the input buffer,
 * when not using any SASL SSF encryption layers. Will read as much
 * data as possible without blocking.
 *
1471 1472 1473
 * Returns the number of bytes read, which may be less than
 * the requested 'datalen' if the socket would block. Returns
 * 0 on I/O error or EOF, and disconnects the client socket.
1474
 */
1475
static size_t vnc_client_read_plain(VncState *vs)
1476
{
1477
    size_t ret;
1478
    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
1479 1480 1481 1482 1483
              vs->input.buffer, vs->input.capacity, vs->input.offset);
    buffer_reserve(&vs->input, 4096);
    ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
    if (!ret)
        return 0;
B
bellard 已提交
1484
    vs->input.offset += ret;
1485 1486 1487
    return ret;
}

1488 1489 1490 1491
static void vnc_jobs_bh(void *opaque)
{
    VncState *vs = opaque;

1492
    assert(vs->magic == VNC_MAGIC);
1493 1494
    vnc_jobs_consume_buffer(vs);
}
1495 1496 1497 1498 1499

/*
 * First function called whenever there is more data to be read from
 * the client socket. Will delegate actual work according to whether
 * SASL SSF layers are enabled (thus requiring decryption calls)
1500
 * Returns 0 on success, -1 if client disconnected
1501
 */
1502
static int vnc_client_read(VncState *vs)
1503
{
1504
    size_t ret;
1505 1506 1507 1508 1509 1510

#ifdef CONFIG_VNC_SASL
    if (vs->sasl.conn && vs->sasl.runSSF)
        ret = vnc_client_read_sasl(vs);
    else
#endif /* CONFIG_VNC_SASL */
1511
        ret = vnc_client_read_plain(vs);
1512
    if (!ret) {
1513
        if (vs->disconnecting) {
1514
            vnc_disconnect_finish(vs);
1515
            return -1;
1516
        }
1517
        return 0;
1518
    }
B
bellard 已提交
1519 1520

    while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
1521 1522 1523 1524
        size_t len = vs->read_handler_expect;
        int ret;

        ret = vs->read_handler(vs, vs->input.buffer, len);
1525
        if (vs->disconnecting) {
1526
            vnc_disconnect_finish(vs);
1527
            return -1;
1528
        }
1529 1530

        if (!ret) {
T
Tim Hardeck 已提交
1531
            buffer_advance(&vs->input, len);
1532 1533 1534
        } else {
            vs->read_handler_expect = ret;
        }
B
bellard 已提交
1535
    }
1536
    return 0;
B
bellard 已提交
1537 1538
}

1539 1540 1541 1542
gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED,
                       GIOCondition condition, void *opaque)
{
    VncState *vs = opaque;
1543 1544

    assert(vs->magic == VNC_MAGIC);
1545
    if (condition & G_IO_IN) {
1546
        if (vnc_client_read(vs) < 0) {
G
Gerd Hoffmann 已提交
1547 1548
            /* vs is free()ed here */
            return TRUE;
1549
        }
1550 1551 1552 1553
    }
    if (condition & G_IO_OUT) {
        vnc_client_write(vs);
    }
G
Gerd Hoffmann 已提交
1554

1555 1556 1557 1558 1559 1560
    if (vs->disconnecting) {
        if (vs->ioc_tag != 0) {
            g_source_remove(vs->ioc_tag);
        }
        vs->ioc_tag = 0;
    }
1561 1562 1563 1564
    return TRUE;
}


1565 1566 1567 1568 1569 1570 1571 1572 1573
/*
 * Scale factor to apply to vs->throttle_output_offset when checking for
 * hard limit. Worst case normal usage could be x2, if we have a complete
 * incremental update and complete forced update in the output buffer.
 * So x3 should be good enough, but we pick x5 to be conservative and thus
 * (hopefully) never trigger incorrectly.
 */
#define VNC_THROTTLE_OUTPUT_LIMIT_SCALE 5

1574
void vnc_write(VncState *vs, const void *data, size_t len)
B
bellard 已提交
1575
{
1576
    assert(vs->magic == VNC_MAGIC);
1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591
    if (vs->disconnecting) {
        return;
    }
    /* Protection against malicious client/guest to prevent our output
     * buffer growing without bound if client stops reading data. This
     * should rarely trigger, because we have earlier throttling code
     * which stops issuing framebuffer updates and drops audio data
     * if the throttle_output_offset value is exceeded. So we only reach
     * this higher level if a huge number of pseudo-encodings get
     * triggered while data can't be sent on the socket.
     *
     * NB throttle_output_offset can be zero during early protocol
     * handshake, or from the job thread's VncState clone
     */
    if (vs->throttle_output_offset != 0 &&
1592 1593
        (vs->output.offset / VNC_THROTTLE_OUTPUT_LIMIT_SCALE) >
        vs->throttle_output_offset) {
1594 1595
        trace_vnc_client_output_limit(vs, vs->ioc, vs->output.offset,
                                      vs->throttle_output_offset);
1596 1597 1598
        vnc_disconnect_start(vs);
        return;
    }
B
bellard 已提交
1599 1600
    buffer_reserve(&vs->output, len);

1601 1602 1603 1604 1605 1606
    if (vs->ioc != NULL && buffer_empty(&vs->output)) {
        if (vs->ioc_tag) {
            g_source_remove(vs->ioc_tag);
        }
        vs->ioc_tag = qio_channel_add_watch(
            vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL);
B
bellard 已提交
1607 1608 1609 1610 1611
    }

    buffer_append(&vs->output, data, len);
}

1612
void vnc_write_s32(VncState *vs, int32_t value)
B
bellard 已提交
1613 1614 1615 1616
{
    vnc_write_u32(vs, *(uint32_t *)&value);
}

1617
void vnc_write_u32(VncState *vs, uint32_t value)
B
bellard 已提交
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628
{
    uint8_t buf[4];

    buf[0] = (value >> 24) & 0xFF;
    buf[1] = (value >> 16) & 0xFF;
    buf[2] = (value >>  8) & 0xFF;
    buf[3] = value & 0xFF;

    vnc_write(vs, buf, 4);
}

1629
void vnc_write_u16(VncState *vs, uint16_t value)
B
bellard 已提交
1630
{
1631
    uint8_t buf[2];
B
bellard 已提交
1632 1633 1634 1635 1636 1637 1638

    buf[0] = (value >> 8) & 0xFF;
    buf[1] = value & 0xFF;

    vnc_write(vs, buf, 2);
}

1639
void vnc_write_u8(VncState *vs, uint8_t value)
B
bellard 已提交
1640 1641 1642 1643
{
    vnc_write(vs, (char *)&value, 1);
}

1644
void vnc_flush(VncState *vs)
B
bellard 已提交
1645
{
C
Corentin Chary 已提交
1646
    vnc_lock_output(vs);
1647
    if (vs->ioc != NULL && vs->output.offset) {
C
Corentin Chary 已提交
1648 1649
        vnc_client_write_locked(vs);
    }
1650 1651 1652 1653 1654 1655
    if (vs->disconnecting) {
        if (vs->ioc_tag != 0) {
            g_source_remove(vs->ioc_tag);
        }
        vs->ioc_tag = 0;
    }
C
Corentin Chary 已提交
1656
    vnc_unlock_output(vs);
B
bellard 已提交
1657 1658
}

B
Blue Swirl 已提交
1659
static uint8_t read_u8(uint8_t *data, size_t offset)
B
bellard 已提交
1660 1661 1662 1663
{
    return data[offset];
}

B
Blue Swirl 已提交
1664
static uint16_t read_u16(uint8_t *data, size_t offset)
B
bellard 已提交
1665 1666 1667 1668
{
    return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
}

B
Blue Swirl 已提交
1669
static int32_t read_s32(uint8_t *data, size_t offset)
B
bellard 已提交
1670 1671
{
    return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
1672
                     (data[offset + 2] << 8) | data[offset + 3]);
B
bellard 已提交
1673 1674
}

1675
uint32_t read_u32(uint8_t *data, size_t offset)
B
bellard 已提交
1676 1677
{
    return ((data[offset] << 24) | (data[offset + 1] << 16) |
1678
            (data[offset + 2] << 8) | data[offset + 3]);
B
bellard 已提交
1679 1680
}

T
ths 已提交
1681
static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
B
bellard 已提交
1682 1683 1684
{
}

1685
static void check_pointer_type_change(Notifier *notifier, void *data)
1686
{
1687
    VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
1688
    int absolute = qemu_input_is_absolute();
1689

1690
    if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
C
Corentin Chary 已提交
1691
        vnc_lock_output(vs);
1692
        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1693 1694 1695
        vnc_write_u8(vs, 0);
        vnc_write_u16(vs, 1);
        vnc_framebuffer_update(vs, absolute, 0,
1696 1697
                               pixman_image_get_width(vs->vd->server),
                               pixman_image_get_height(vs->vd->server),
1698
                               VNC_ENCODING_POINTER_TYPE_CHANGE);
C
Corentin Chary 已提交
1699
        vnc_unlock_output(vs);
1700
        vnc_flush(vs);
1701 1702 1703 1704
    }
    vs->absolute = absolute;
}

B
bellard 已提交
1705 1706
static void pointer_event(VncState *vs, int button_mask, int x, int y)
{
1707
    static uint32_t bmap[INPUT_BUTTON__MAX] = {
1708 1709 1710
        [INPUT_BUTTON_LEFT]       = 0x01,
        [INPUT_BUTTON_MIDDLE]     = 0x02,
        [INPUT_BUTTON_RIGHT]      = 0x04,
G
Gerd Hoffmann 已提交
1711 1712
        [INPUT_BUTTON_WHEEL_UP]   = 0x08,
        [INPUT_BUTTON_WHEEL_DOWN] = 0x10,
1713 1714
    };
    QemuConsole *con = vs->vd->dcl.con;
1715 1716
    int width = pixman_image_get_width(vs->vd->server);
    int height = pixman_image_get_height(vs->vd->server);
B
bellard 已提交
1717

1718 1719 1720 1721
    if (vs->last_bmask != button_mask) {
        qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
        vs->last_bmask = button_mask;
    }
1722 1723

    if (vs->absolute) {
1724 1725
        qemu_input_queue_abs(con, INPUT_AXIS_X, x, 0, width);
        qemu_input_queue_abs(con, INPUT_AXIS_Y, y, 0, height);
1726
    } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
1727 1728
        qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF);
        qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF);
1729
    } else {
1730 1731 1732 1733
        if (vs->last_x != -1) {
            qemu_input_queue_rel(con, INPUT_AXIS_X, x - vs->last_x);
            qemu_input_queue_rel(con, INPUT_AXIS_Y, y - vs->last_y);
        }
1734 1735
        vs->last_x = x;
        vs->last_y = y;
B
bellard 已提交
1736
    }
1737
    qemu_input_event_sync();
B
bellard 已提交
1738 1739
}

1740 1741 1742 1743 1744
static void reset_keys(VncState *vs)
{
    int i;
    for(i = 0; i < 256; i++) {
        if (vs->modifiers_state[i]) {
1745
            qemu_input_event_send_key_number(vs->vd->dcl.con, i, false);
1746
            qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
1747 1748 1749 1750 1751
            vs->modifiers_state[i] = 0;
        }
    }
}

1752 1753
static void press_key(VncState *vs, int keysym)
{
1754 1755
    int keycode = keysym2scancode(vs->vd->kbd_layout, keysym,
                                  false, false, false) & SCANCODE_KEYMASK;
1756
    qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
1757
    qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
1758
    qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
1759
    qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
1760 1761
}

L
Lei Li 已提交
1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772
static void vnc_led_state_change(VncState *vs)
{
    if (!vnc_has_feature(vs, VNC_FEATURE_LED_STATE)) {
        return;
    }

    vnc_lock_output(vs);
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
    vnc_write_u8(vs, 0);
    vnc_write_u16(vs, 1);
    vnc_framebuffer_update(vs, 0, 0, 1, 1, VNC_ENCODING_LED_STATE);
P
Pierre Ossman 已提交
1773
    vnc_write_u8(vs, vs->vd->ledstate);
L
Lei Li 已提交
1774 1775 1776 1777
    vnc_unlock_output(vs);
    vnc_flush(vs);
}

G
Gerd Hoffmann 已提交
1778 1779
static void kbd_leds(void *opaque, int ledstate)
{
P
Pierre Ossman 已提交
1780 1781
    VncDisplay *vd = opaque;
    VncState *client;
G
Gerd Hoffmann 已提交
1782

1783 1784 1785 1786
    trace_vnc_key_guest_leds((ledstate & QEMU_CAPS_LOCK_LED),
                             (ledstate & QEMU_NUM_LOCK_LED),
                             (ledstate & QEMU_SCROLL_LOCK_LED));

P
Pierre Ossman 已提交
1787 1788
    if (ledstate == vd->ledstate) {
        return;
L
Lei Li 已提交
1789
    }
L
Lei Li 已提交
1790

P
Pierre Ossman 已提交
1791 1792 1793 1794
    vd->ledstate = ledstate;

    QTAILQ_FOREACH(client, &vd->clients, next) {
        vnc_led_state_change(client);
L
Lei Li 已提交
1795
    }
G
Gerd Hoffmann 已提交
1796 1797
}

1798
static void do_key_event(VncState *vs, int down, int keycode, int sym)
B
bellard 已提交
1799
{
1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812
    /* QEMU console switch */
    switch(keycode) {
    case 0x2a:                          /* Left Shift */
    case 0x36:                          /* Right Shift */
    case 0x1d:                          /* Left CTRL */
    case 0x9d:                          /* Right CTRL */
    case 0x38:                          /* Left ALT */
    case 0xb8:                          /* Right ALT */
        if (down)
            vs->modifiers_state[keycode] = 1;
        else
            vs->modifiers_state[keycode] = 0;
        break;
1813
    case 0x02 ... 0x0a: /* '1' to '9' keys */
1814 1815
        if (vs->vd->dcl.con == NULL &&
            down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1816 1817 1818 1819 1820 1821
            /* Reset the modifiers sent to the current console */
            reset_keys(vs);
            console_select(keycode - 0x02);
            return;
        }
        break;
1822 1823
    case 0x3a:                        /* CapsLock */
    case 0x45:                        /* NumLock */
G
Gerd Hoffmann 已提交
1824
        if (down)
1825 1826 1827 1828
            vs->modifiers_state[keycode] ^= 1;
        break;
    }

1829 1830 1831
    /* Turn off the lock state sync logic if the client support the led
       state extension.
    */
1832
    if (down && vs->vd->lock_key_sync &&
1833
        !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
G
Gerd Hoffmann 已提交
1834
        keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
1835 1836 1837 1838
        /* If the numlock state needs to change then simulate an additional
           keypress before sending this one.  This will happen if the user
           toggles numlock away from the VNC window.
        */
1839
        if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
1840
            if (!vs->modifiers_state[0x45]) {
1841
                trace_vnc_key_sync_numlock(true);
1842 1843 1844 1845 1846
                vs->modifiers_state[0x45] = 1;
                press_key(vs, 0xff7f);
            }
        } else {
            if (vs->modifiers_state[0x45]) {
1847
                trace_vnc_key_sync_numlock(false);
1848 1849 1850 1851
                vs->modifiers_state[0x45] = 0;
                press_key(vs, 0xff7f);
            }
        }
1852
    }
B
bellard 已提交
1853

1854
    if (down && vs->vd->lock_key_sync &&
1855
        !vnc_has_feature(vs, VNC_FEATURE_LED_STATE) &&
G
Gerd Hoffmann 已提交
1856
        ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
G
Gerd Hoffmann 已提交
1857 1858 1859 1860 1861 1862 1863 1864 1865
        /* If the capslock state needs to change then simulate an additional
           keypress before sending this one.  This will happen if the user
           toggles capslock away from the VNC window.
        */
        int uppercase = !!(sym >= 'A' && sym <= 'Z');
        int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
        int capslock = !!(vs->modifiers_state[0x3a]);
        if (capslock) {
            if (uppercase == shift) {
1866
                trace_vnc_key_sync_capslock(false);
G
Gerd Hoffmann 已提交
1867 1868 1869 1870 1871
                vs->modifiers_state[0x3a] = 0;
                press_key(vs, 0xffe5);
            }
        } else {
            if (uppercase != shift) {
1872
                trace_vnc_key_sync_capslock(true);
G
Gerd Hoffmann 已提交
1873 1874 1875 1876 1877 1878
                vs->modifiers_state[0x3a] = 1;
                press_key(vs, 0xffe5);
            }
        }
    }

G
Gerd Hoffmann 已提交
1879
    if (qemu_console_is_graphic(NULL)) {
1880
        qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
1881
        qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
1882
    } else {
1883 1884 1885
        bool numlock = vs->modifiers_state[0x45];
        bool control = (vs->modifiers_state[0x1d] ||
                        vs->modifiers_state[0x9d]);
1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922
        /* QEMU console emulation */
        if (down) {
            switch (keycode) {
            case 0x2a:                          /* Left Shift */
            case 0x36:                          /* Right Shift */
            case 0x1d:                          /* Left CTRL */
            case 0x9d:                          /* Right CTRL */
            case 0x38:                          /* Left ALT */
            case 0xb8:                          /* Right ALT */
                break;
            case 0xc8:
                kbd_put_keysym(QEMU_KEY_UP);
                break;
            case 0xd0:
                kbd_put_keysym(QEMU_KEY_DOWN);
                break;
            case 0xcb:
                kbd_put_keysym(QEMU_KEY_LEFT);
                break;
            case 0xcd:
                kbd_put_keysym(QEMU_KEY_RIGHT);
                break;
            case 0xd3:
                kbd_put_keysym(QEMU_KEY_DELETE);
                break;
            case 0xc7:
                kbd_put_keysym(QEMU_KEY_HOME);
                break;
            case 0xcf:
                kbd_put_keysym(QEMU_KEY_END);
                break;
            case 0xc9:
                kbd_put_keysym(QEMU_KEY_PAGEUP);
                break;
            case 0xd1:
                kbd_put_keysym(QEMU_KEY_PAGEDOWN);
                break;
1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973

            case 0x47:
                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
                break;
            case 0x48:
                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
                break;
            case 0x49:
                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
                break;
            case 0x4b:
                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
                break;
            case 0x4c:
                kbd_put_keysym('5');
                break;
            case 0x4d:
                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
                break;
            case 0x4f:
                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
                break;
            case 0x50:
                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
                break;
            case 0x51:
                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
                break;
            case 0x52:
                kbd_put_keysym('0');
                break;
            case 0x53:
                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
                break;

            case 0xb5:
                kbd_put_keysym('/');
                break;
            case 0x37:
                kbd_put_keysym('*');
                break;
            case 0x4a:
                kbd_put_keysym('-');
                break;
            case 0x4e:
                kbd_put_keysym('+');
                break;
            case 0x9c:
                kbd_put_keysym('\n');
                break;

1974
            default:
1975 1976 1977 1978 1979
                if (control) {
                    kbd_put_keysym(sym & 0x1f);
                } else {
                    kbd_put_keysym(sym);
                }
1980 1981 1982 1983
                break;
            }
        }
    }
B
bellard 已提交
1984 1985
}

1986 1987 1988 1989 1990 1991 1992 1993
static void vnc_release_modifiers(VncState *vs)
{
    static const int keycodes[] = {
        /* shift, control, alt keys, both left & right */
        0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8,
    };
    int i, keycode;

G
Gerd Hoffmann 已提交
1994
    if (!qemu_console_is_graphic(NULL)) {
1995 1996 1997 1998 1999 2000 2001
        return;
    }
    for (i = 0; i < ARRAY_SIZE(keycodes); i++) {
        keycode = keycodes[i];
        if (!vs->modifiers_state[keycode]) {
            continue;
        }
2002
        qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
2003
        qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
2004 2005 2006
    }
}

2007 2008
static const char *code2name(int keycode)
{
2009
    return QKeyCode_str(qemu_input_key_number_to_qcode(keycode));
2010 2011
}

B
bellard 已提交
2012 2013
static void key_event(VncState *vs, int down, uint32_t sym)
{
2014 2015 2016
    bool shift = vs->modifiers_state[0x2a] || vs->modifiers_state[0x36];
    bool altgr = vs->modifiers_state[0xb8];
    bool ctrl  = vs->modifiers_state[0x1d] || vs->modifiers_state[0x9d];
2017
    int keycode;
G
Gerd Hoffmann 已提交
2018
    int lsym = sym;
2019

G
Gerd Hoffmann 已提交
2020
    if (lsym >= 'A' && lsym <= 'Z' && qemu_console_is_graphic(NULL)) {
G
Gerd Hoffmann 已提交
2021 2022
        lsym = lsym - 'A' + 'a';
    }
2023

2024 2025
    keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF,
                              shift, altgr, ctrl) & SCANCODE_KEYMASK;
2026
    trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
2027 2028 2029 2030 2031 2032 2033
    do_key_event(vs, down, keycode, sym);
}

static void ext_key_event(VncState *vs, int down,
                          uint32_t sym, uint16_t keycode)
{
    /* if the user specifies a keyboard layout, always use it */
2034
    if (keyboard_layout) {
2035
        key_event(vs, down, sym);
2036 2037
    } else {
        trace_vnc_key_event_ext(down, sym, keycode, code2name(keycode));
2038
        do_key_event(vs, down, keycode, sym);
2039
    }
B
bellard 已提交
2040 2041
}

B
bellard 已提交
2042
static void framebuffer_update_request(VncState *vs, int incremental,
2043
                                       int x, int y, int w, int h)
B
bellard 已提交
2044
{
2045
    if (incremental) {
2046 2047 2048 2049 2050 2051
        if (vs->update != VNC_STATE_UPDATE_FORCE) {
            vs->update = VNC_STATE_UPDATE_INCREMENTAL;
        }
    } else {
        vs->update = VNC_STATE_UPDATE_FORCE;
        vnc_set_area_dirty(vs->dirty, vs->vd, x, y, w, h);
B
bellard 已提交
2052 2053 2054
    }
}

2055 2056
static void send_ext_key_event_ack(VncState *vs)
{
C
Corentin Chary 已提交
2057
    vnc_lock_output(vs);
2058
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
2059 2060
    vnc_write_u8(vs, 0);
    vnc_write_u16(vs, 1);
G
Gerd Hoffmann 已提交
2061
    vnc_framebuffer_update(vs, 0, 0,
2062 2063
                           pixman_image_get_width(vs->vd->server),
                           pixman_image_get_height(vs->vd->server),
2064
                           VNC_ENCODING_EXT_KEY_EVENT);
C
Corentin Chary 已提交
2065
    vnc_unlock_output(vs);
2066 2067 2068
    vnc_flush(vs);
}

M
malc 已提交
2069 2070
static void send_ext_audio_ack(VncState *vs)
{
C
Corentin Chary 已提交
2071
    vnc_lock_output(vs);
2072
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
M
malc 已提交
2073 2074
    vnc_write_u8(vs, 0);
    vnc_write_u16(vs, 1);
G
Gerd Hoffmann 已提交
2075
    vnc_framebuffer_update(vs, 0, 0,
2076 2077
                           pixman_image_get_width(vs->vd->server),
                           pixman_image_get_height(vs->vd->server),
2078
                           VNC_ENCODING_AUDIO);
C
Corentin Chary 已提交
2079
    vnc_unlock_output(vs);
M
malc 已提交
2080 2081 2082
    vnc_flush(vs);
}

B
bellard 已提交
2083 2084 2085
static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
{
    int i;
2086
    unsigned int enc = 0;
B
bellard 已提交
2087

2088
    vs->features = 0;
2089
    vs->vnc_encoding = 0;
2090 2091
    vs->tight.compression = 9;
    vs->tight.quality = -1; /* Lossless by default */
2092
    vs->absolute = -1;
B
bellard 已提交
2093

2094 2095
    /*
     * Start from the end because the encodings are sent in order of preference.
D
Dong Xu Wang 已提交
2096
     * This way the preferred encoding (first encoding defined in the array)
2097 2098
     * will be set at the end of the loop.
     */
B
bellard 已提交
2099
    for (i = n_encodings - 1; i >= 0; i--) {
2100 2101 2102
        enc = encodings[i];
        switch (enc) {
        case VNC_ENCODING_RAW:
2103
            vs->vnc_encoding = enc;
2104 2105
            break;
        case VNC_ENCODING_COPYRECT:
2106
            vs->features |= VNC_FEATURE_COPYRECT_MASK;
2107 2108 2109
            break;
        case VNC_ENCODING_HEXTILE:
            vs->features |= VNC_FEATURE_HEXTILE_MASK;
2110
            vs->vnc_encoding = enc;
2111
            break;
C
Corentin Chary 已提交
2112 2113 2114 2115
        case VNC_ENCODING_TIGHT:
            vs->features |= VNC_FEATURE_TIGHT_MASK;
            vs->vnc_encoding = enc;
            break;
2116
#ifdef CONFIG_VNC_PNG
C
Corentin Chary 已提交
2117 2118 2119 2120
        case VNC_ENCODING_TIGHT_PNG:
            vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
            vs->vnc_encoding = enc;
            break;
2121
#endif
2122 2123
        case VNC_ENCODING_ZLIB:
            vs->features |= VNC_FEATURE_ZLIB_MASK;
2124
            vs->vnc_encoding = enc;
2125
            break;
2126 2127 2128 2129 2130 2131 2132 2133
        case VNC_ENCODING_ZRLE:
            vs->features |= VNC_FEATURE_ZRLE_MASK;
            vs->vnc_encoding = enc;
            break;
        case VNC_ENCODING_ZYWRLE:
            vs->features |= VNC_FEATURE_ZYWRLE_MASK;
            vs->vnc_encoding = enc;
            break;
2134 2135 2136 2137 2138 2139
        case VNC_ENCODING_DESKTOPRESIZE:
            vs->features |= VNC_FEATURE_RESIZE_MASK;
            break;
        case VNC_ENCODING_POINTER_TYPE_CHANGE:
            vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
            break;
G
Gerd Hoffmann 已提交
2140 2141
        case VNC_ENCODING_RICH_CURSOR:
            vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
2142 2143 2144
            if (vs->vd->cursor) {
                vnc_cursor_define(vs);
            }
G
Gerd Hoffmann 已提交
2145
            break;
2146
        case VNC_ENCODING_EXT_KEY_EVENT:
2147 2148
            send_ext_key_event_ack(vs);
            break;
2149
        case VNC_ENCODING_AUDIO:
M
malc 已提交
2150 2151
            send_ext_audio_ack(vs);
            break;
2152 2153
        case VNC_ENCODING_WMVi:
            vs->features |= VNC_FEATURE_WMVI_MASK;
2154
            break;
L
Lei Li 已提交
2155 2156 2157
        case VNC_ENCODING_LED_STATE:
            vs->features |= VNC_FEATURE_LED_STATE_MASK;
            break;
2158
        case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
2159
            vs->tight.compression = (enc & 0x0F);
2160 2161
            break;
        case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
2162 2163 2164
            if (vs->vd->lossy) {
                vs->tight.quality = (enc & 0x0F);
            }
2165
            break;
2166 2167 2168 2169
        default:
            VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
            break;
        }
B
bellard 已提交
2170
    }
2171
    vnc_desktop_resize(vs);
2172
    check_pointer_type_change(&vs->mouse_mode_notifier, NULL);
L
Lei Li 已提交
2173
    vnc_led_state_change(vs);
B
bellard 已提交
2174 2175
}

2176 2177
static void set_pixel_conversion(VncState *vs)
{
2178 2179 2180
    pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf);

    if (fmt == VNC_SERVER_FB_FORMAT) {
2181
        vs->write_pixels = vnc_write_pixels_copy;
2182
        vnc_hextile_set_pixel_conversion(vs, 0);
2183 2184
    } else {
        vs->write_pixels = vnc_write_pixels_generic;
2185
        vnc_hextile_set_pixel_conversion(vs, 1);
2186 2187 2188
    }
}

A
Alexander Graf 已提交
2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206
static void send_color_map(VncState *vs)
{
    int i;

    vnc_write_u8(vs, VNC_MSG_SERVER_SET_COLOUR_MAP_ENTRIES);
    vnc_write_u8(vs,  0);    /* padding     */
    vnc_write_u16(vs, 0);    /* first color */
    vnc_write_u16(vs, 256);  /* # of colors */

    for (i = 0; i < 256; i++) {
        PixelFormat *pf = &vs->client_pf;

        vnc_write_u16(vs, (((i >> pf->rshift) & pf->rmax) << (16 - pf->rbits)));
        vnc_write_u16(vs, (((i >> pf->gshift) & pf->gmax) << (16 - pf->gbits)));
        vnc_write_u16(vs, (((i >> pf->bshift) & pf->bmax) << (16 - pf->bbits)));
    }
}

2207
static void set_pixel_format(VncState *vs, int bits_per_pixel,
2208 2209 2210
                             int big_endian_flag, int true_color_flag,
                             int red_max, int green_max, int blue_max,
                             int red_shift, int green_shift, int blue_shift)
B
bellard 已提交
2211
{
B
bellard 已提交
2212
    if (!true_color_flag) {
A
Alexander Graf 已提交
2213 2214 2215 2216 2217 2218 2219 2220
        /* Expose a reasonable default 256 color map */
        bits_per_pixel = 8;
        red_max = 7;
        green_max = 7;
        blue_max = 3;
        red_shift = 0;
        green_shift = 3;
        blue_shift = 6;
B
bellard 已提交
2221
    }
B
bellard 已提交
2222

2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
    switch (bits_per_pixel) {
    case 8:
    case 16:
    case 32:
        break;
    default:
        vnc_client_error(vs);
        return;
    }

2233
    vs->client_pf.rmax = red_max ? red_max : 0xFF;
2234
    vs->client_pf.rbits = ctpopl(red_max);
2235 2236
    vs->client_pf.rshift = red_shift;
    vs->client_pf.rmask = red_max << red_shift;
2237
    vs->client_pf.gmax = green_max ? green_max : 0xFF;
2238
    vs->client_pf.gbits = ctpopl(green_max);
2239 2240
    vs->client_pf.gshift = green_shift;
    vs->client_pf.gmask = green_max << green_shift;
2241
    vs->client_pf.bmax = blue_max ? blue_max : 0xFF;
2242
    vs->client_pf.bbits = ctpopl(blue_max);
2243 2244 2245 2246 2247 2248
    vs->client_pf.bshift = blue_shift;
    vs->client_pf.bmask = blue_max << blue_shift;
    vs->client_pf.bits_per_pixel = bits_per_pixel;
    vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
    vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
    vs->client_be = big_endian_flag;
2249

A
Alexander Graf 已提交
2250 2251 2252 2253
    if (!true_color_flag) {
        send_color_map(vs);
    }

2254
    set_pixel_conversion(vs);
B
bellard 已提交
2255

2256 2257
    graphic_hw_invalidate(vs->vd->dcl.con);
    graphic_hw_update(vs->vd->dcl.con);
B
bellard 已提交
2258 2259
}

2260 2261 2262
static void pixel_format_message (VncState *vs) {
    char pad[3] = { 0, 0, 0 };

2263 2264 2265 2266
    vs->client_pf = qemu_default_pixelformat(32);

    vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */
    vnc_write_u8(vs, vs->client_pf.depth); /* depth */
2267

2268
#ifdef HOST_WORDS_BIGENDIAN
2269 2270 2271 2272 2273
    vnc_write_u8(vs, 1);             /* big-endian-flag */
#else
    vnc_write_u8(vs, 0);             /* big-endian-flag */
#endif
    vnc_write_u8(vs, 1);             /* true-color-flag */
2274 2275 2276 2277 2278 2279 2280
    vnc_write_u16(vs, vs->client_pf.rmax);     /* red-max */
    vnc_write_u16(vs, vs->client_pf.gmax);     /* green-max */
    vnc_write_u16(vs, vs->client_pf.bmax);     /* blue-max */
    vnc_write_u8(vs, vs->client_pf.rshift);    /* red-shift */
    vnc_write_u8(vs, vs->client_pf.gshift);    /* green-shift */
    vnc_write_u8(vs, vs->client_pf.bshift);    /* blue-shift */
    vnc_write(vs, pad, 3);           /* padding */
2281 2282

    vnc_hextile_set_pixel_conversion(vs, 0);
2283 2284 2285
    vs->write_pixels = vnc_write_pixels_copy;
}

2286
static void vnc_colordepth(VncState *vs)
2287
{
2288
    if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
2289
        /* Sending a WMVi message to notify the client*/
C
Corentin Chary 已提交
2290
        vnc_lock_output(vs);
2291
        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
2292 2293
        vnc_write_u8(vs, 0);
        vnc_write_u16(vs, 1); /* number of rects */
G
Gerd Hoffmann 已提交
2294
        vnc_framebuffer_update(vs, 0, 0,
2295 2296
                               pixman_image_get_width(vs->vd->server),
                               pixman_image_get_height(vs->vd->server),
G
Gerd Hoffmann 已提交
2297
                               VNC_ENCODING_WMVi);
2298
        pixel_format_message(vs);
C
Corentin Chary 已提交
2299
        vnc_unlock_output(vs);
2300
        vnc_flush(vs);
2301
    } else {
2302
        set_pixel_conversion(vs);
2303 2304 2305
    }
}

T
ths 已提交
2306
static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
B
bellard 已提交
2307 2308 2309
{
    int i;
    uint16_t limit;
2310
    uint32_t freq;
S
Stefano Stabellini 已提交
2311 2312 2313
    VncDisplay *vd = vs->vd;

    if (data[0] > 3) {
G
Gerd Hoffmann 已提交
2314
        update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
S
Stefano Stabellini 已提交
2315
    }
B
bellard 已提交
2316 2317

    switch (data[0]) {
2318
    case VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
2319 2320 2321
        if (len == 1)
            return 20;

2322
        set_pixel_format(vs, read_u8(data, 4),
2323 2324 2325 2326 2327
                         read_u8(data, 6), read_u8(data, 7),
                         read_u16(data, 8), read_u16(data, 10),
                         read_u16(data, 12), read_u8(data, 14),
                         read_u8(data, 15), read_u8(data, 16));
        break;
2328
    case VNC_MSG_CLIENT_SET_ENCODINGS:
2329 2330
        if (len == 1)
            return 4;
B
bellard 已提交
2331

2332
        if (len == 4) {
2333 2334 2335 2336 2337
            limit = read_u16(data, 2);
            if (limit > 0)
                return 4 + (limit * 4);
        } else
            limit = read_u16(data, 2);
B
bellard 已提交
2338

2339 2340 2341 2342
        for (i = 0; i < limit; i++) {
            int32_t val = read_s32(data, 4 + (i * 4));
            memcpy(data + 4 + (i * 4), &val, sizeof(val));
        }
B
bellard 已提交
2343

2344 2345
        set_encodings(vs, (int32_t *)(data + 4), limit);
        break;
2346
    case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
2347 2348
        if (len == 1)
            return 10;
B
bellard 已提交
2349

2350 2351 2352 2353
        framebuffer_update_request(vs,
                                   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
                                   read_u16(data, 6), read_u16(data, 8));
        break;
2354
    case VNC_MSG_CLIENT_KEY_EVENT:
2355 2356
        if (len == 1)
            return 8;
B
bellard 已提交
2357

2358 2359
        key_event(vs, read_u8(data, 1), read_u32(data, 4));
        break;
2360
    case VNC_MSG_CLIENT_POINTER_EVENT:
2361 2362
        if (len == 1)
            return 6;
B
bellard 已提交
2363

2364 2365
        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
        break;
2366
    case VNC_MSG_CLIENT_CUT_TEXT:
2367
        if (len == 1) {
2368
            return 8;
2369
        }
2370
        if (len == 8) {
2371
            uint32_t dlen = read_u32(data, 4);
2372 2373 2374 2375 2376 2377 2378
            if (dlen > (1 << 20)) {
                error_report("vnc: client_cut_text msg payload has %u bytes"
                             " which exceeds our limit of 1MB.", dlen);
                vnc_client_error(vs);
                break;
            }
            if (dlen > 0) {
2379
                return 8 + dlen;
2380
            }
2381
        }
B
bellard 已提交
2382

2383 2384
        client_cut_text(vs, read_u32(data, 4), data + 8);
        break;
2385
    case VNC_MSG_CLIENT_QEMU:
2386 2387 2388 2389
        if (len == 1)
            return 2;

        switch (read_u8(data, 1)) {
2390
        case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
2391 2392 2393 2394 2395 2396
            if (len == 2)
                return 12;

            ext_key_event(vs, read_u16(data, 2),
                          read_u32(data, 4), read_u32(data, 8));
            break;
2397
        case VNC_MSG_CLIENT_QEMU_AUDIO:
M
malc 已提交
2398 2399 2400 2401
            if (len == 2)
                return 4;

            switch (read_u16 (data, 2)) {
2402
            case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
M
malc 已提交
2403 2404
                audio_add(vs);
                break;
2405
            case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
M
malc 已提交
2406 2407
                audio_del(vs);
                break;
2408
            case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
M
malc 已提交
2409 2410 2411 2412 2413 2414 2415 2416 2417 2418
                if (len == 4)
                    return 10;
                switch (read_u8(data, 4)) {
                case 0: vs->as.fmt = AUD_FMT_U8; break;
                case 1: vs->as.fmt = AUD_FMT_S8; break;
                case 2: vs->as.fmt = AUD_FMT_U16; break;
                case 3: vs->as.fmt = AUD_FMT_S16; break;
                case 4: vs->as.fmt = AUD_FMT_U32; break;
                case 5: vs->as.fmt = AUD_FMT_S32; break;
                default:
2419
                    VNC_DEBUG("Invalid audio format %d\n", read_u8(data, 4));
M
malc 已提交
2420 2421 2422 2423 2424
                    vnc_client_error(vs);
                    break;
                }
                vs->as.nchannels = read_u8(data, 5);
                if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
M
Marc-André Lureau 已提交
2425
                    VNC_DEBUG("Invalid audio channel count %d\n",
2426
                              read_u8(data, 5));
M
malc 已提交
2427 2428 2429
                    vnc_client_error(vs);
                    break;
                }
2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440
                freq = read_u32(data, 6);
                /* No official limit for protocol, but 48khz is a sensible
                 * upper bound for trustworthy clients, and this limit
                 * protects calculations involving 'vs->as.freq' later.
                 */
                if (freq > 48000) {
                    VNC_DEBUG("Invalid audio frequency %u > 48000", freq);
                    vnc_client_error(vs);
                    break;
                }
                vs->as.freq = freq;
M
malc 已提交
2441 2442
                break;
            default:
2443
                VNC_DEBUG("Invalid audio message %d\n", read_u8(data, 4));
M
malc 已提交
2444 2445 2446 2447 2448
                vnc_client_error(vs);
                break;
            }
            break;

2449
        default:
2450
            VNC_DEBUG("Msg: %d\n", read_u16(data, 0));
2451 2452 2453 2454
            vnc_client_error(vs);
            break;
        }
        break;
B
bellard 已提交
2455
    default:
2456
        VNC_DEBUG("Msg: %d\n", data[0]);
2457 2458
        vnc_client_error(vs);
        break;
B
bellard 已提交
2459
    }
2460

2461
    vnc_update_throttle_offset(vs);
B
bellard 已提交
2462 2463 2464 2465
    vnc_read_when(vs, protocol_client_msg, 1);
    return 0;
}

T
ths 已提交
2466
static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
B
bellard 已提交
2467
{
T
ths 已提交
2468
    char buf[1024];
2469
    VncShareMode mode;
T
ths 已提交
2470
    int size;
B
bellard 已提交
2471

2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529
    mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE;
    switch (vs->vd->share_policy) {
    case VNC_SHARE_POLICY_IGNORE:
        /*
         * Ignore the shared flag.  Nothing to do here.
         *
         * Doesn't conform to the rfb spec but is traditional qemu
         * behavior, thus left here as option for compatibility
         * reasons.
         */
        break;
    case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE:
        /*
         * Policy: Allow clients ask for exclusive access.
         *
         * Implementation: When a client asks for exclusive access,
         * disconnect all others. Shared connects are allowed as long
         * as no exclusive connection exists.
         *
         * This is how the rfb spec suggests to handle the shared flag.
         */
        if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
            VncState *client;
            QTAILQ_FOREACH(client, &vs->vd->clients, next) {
                if (vs == client) {
                    continue;
                }
                if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE &&
                    client->share_mode != VNC_SHARE_MODE_SHARED) {
                    continue;
                }
                vnc_disconnect_start(client);
            }
        }
        if (mode == VNC_SHARE_MODE_SHARED) {
            if (vs->vd->num_exclusive > 0) {
                vnc_disconnect_start(vs);
                return 0;
            }
        }
        break;
    case VNC_SHARE_POLICY_FORCE_SHARED:
        /*
         * Policy: Shared connects only.
         * Implementation: Disallow clients asking for exclusive access.
         *
         * Useful for shared desktop sessions where you don't want
         * someone forgetting to say -shared when running the vnc
         * client disconnect everybody else.
         */
        if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
            vnc_disconnect_start(vs);
            return 0;
        }
        break;
    }
    vnc_set_share_mode(vs, mode);

G
Gerd Hoffmann 已提交
2530 2531 2532 2533 2534
    if (vs->vd->num_shared > vs->vd->connections_limit) {
        vnc_disconnect_start(vs);
        return 0;
    }

2535 2536 2537 2538
    assert(pixman_image_get_width(vs->vd->server) < 65536 &&
           pixman_image_get_width(vs->vd->server) >= 0);
    assert(pixman_image_get_height(vs->vd->server) < 65536 &&
           pixman_image_get_height(vs->vd->server) >= 0);
2539 2540
    vs->client_width = pixman_image_get_width(vs->vd->server);
    vs->client_height = pixman_image_get_height(vs->vd->server);
2541 2542
    vnc_write_u16(vs, vs->client_width);
    vnc_write_u16(vs, vs->client_height);
B
bellard 已提交
2543

2544
    pixel_format_message(vs);
B
bellard 已提交
2545

2546
    if (qemu_name) {
T
ths 已提交
2547
        size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
2548 2549 2550 2551
        if (size > sizeof(buf)) {
            size = sizeof(buf);
        }
    } else {
T
ths 已提交
2552
        size = snprintf(buf, sizeof(buf), "QEMU");
2553
    }
T
ths 已提交
2554 2555 2556

    vnc_write_u32(vs, size);
    vnc_write(vs, buf, size);
B
bellard 已提交
2557 2558
    vnc_flush(vs);

2559
    vnc_client_cache_auth(vs);
W
Wenchao Xia 已提交
2560
    vnc_qmp_event(vs, QAPI_EVENT_VNC_INITIALIZED);
2561

B
bellard 已提交
2562 2563 2564 2565 2566
    vnc_read_when(vs, protocol_client_msg, 1);

    return 0;
}

2567 2568 2569 2570 2571
void start_client_init(VncState *vs)
{
    vnc_read_when(vs, protocol_client_init, 1);
}

2572 2573 2574 2575 2576 2577 2578 2579 2580 2581
static void make_challenge(VncState *vs)
{
    int i;

    srand(time(NULL)+getpid()+getpid()*987654+rand());

    for (i = 0 ; i < sizeof(vs->challenge) ; i++)
        vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
}

T
ths 已提交
2582
static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
2583
{
T
ths 已提交
2584
    unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
2585
    size_t i, pwlen;
T
ths 已提交
2586
    unsigned char key[8];
G
Gerd Hoffmann 已提交
2587
    time_t now = time(NULL);
G
Gonglei 已提交
2588
    QCryptoCipher *cipher = NULL;
2589
    Error *err = NULL;
2590

2591
    if (!vs->vd->password) {
2592
        trace_vnc_auth_fail(vs, vs->auth, "password is not set", "");
G
Gerd Hoffmann 已提交
2593
        goto reject;
2594
    }
G
Gerd Hoffmann 已提交
2595
    if (vs->vd->expires < now) {
2596
        trace_vnc_auth_fail(vs, vs->auth, "password is expired", "");
G
Gerd Hoffmann 已提交
2597 2598
        goto reject;
    }
2599 2600 2601 2602

    memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);

    /* Calculate the expected challenge response */
2603
    pwlen = strlen(vs->vd->password);
2604
    for (i=0; i<sizeof(key); i++)
2605
        key[i] = i<pwlen ? vs->vd->password[i] : 0;
2606 2607 2608 2609 2610 2611 2612

    cipher = qcrypto_cipher_new(
        QCRYPTO_CIPHER_ALG_DES_RFB,
        QCRYPTO_CIPHER_MODE_ECB,
        key, G_N_ELEMENTS(key),
        &err);
    if (!cipher) {
2613 2614
        trace_vnc_auth_fail(vs, vs->auth, "cannot create cipher",
                            error_get_pretty(err));
2615 2616 2617 2618
        error_free(err);
        goto reject;
    }

2619
    if (qcrypto_cipher_encrypt(cipher,
2620 2621 2622 2623
                               vs->challenge,
                               response,
                               VNC_AUTH_CHALLENGE_SIZE,
                               &err) < 0) {
2624 2625
        trace_vnc_auth_fail(vs, vs->auth, "cannot encrypt challenge response",
                            error_get_pretty(err));
2626 2627 2628
        error_free(err);
        goto reject;
    }
2629 2630 2631

    /* Compare expected vs actual challenge response */
    if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
2632
        trace_vnc_auth_fail(vs, vs->auth, "mis-matched challenge response", "");
G
Gerd Hoffmann 已提交
2633
        goto reject;
2634
    } else {
2635
        trace_vnc_auth_pass(vs, vs->auth);
2636 2637
        vnc_write_u32(vs, 0); /* Accept auth */
        vnc_flush(vs);
2638

2639
        start_client_init(vs);
2640
    }
G
Gonglei 已提交
2641 2642

    qcrypto_cipher_free(cipher);
2643
    return 0;
G
Gerd Hoffmann 已提交
2644 2645 2646 2647 2648 2649 2650 2651 2652 2653

reject:
    vnc_write_u32(vs, 1); /* Reject auth */
    if (vs->minor >= 8) {
        static const char err[] = "Authentication failed";
        vnc_write_u32(vs, sizeof(err));
        vnc_write(vs, err, sizeof(err));
    }
    vnc_flush(vs);
    vnc_client_error(vs);
G
Gonglei 已提交
2654
    qcrypto_cipher_free(cipher);
G
Gerd Hoffmann 已提交
2655
    return 0;
2656 2657
}

2658
void start_auth_vnc(VncState *vs)
2659 2660 2661 2662 2663 2664 2665
{
    make_challenge(vs);
    /* Send client a 'random' challenge */
    vnc_write(vs, vs->challenge, sizeof(vs->challenge));
    vnc_flush(vs);

    vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
2666 2667 2668
}


T
ths 已提交
2669
static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
2670 2671 2672
{
    /* We only advertise 1 auth scheme at a time, so client
     * must pick the one we sent. Verify this */
2673
    if (data[0] != vs->auth) { /* Reject auth */
2674
       trace_vnc_auth_reject(vs, vs->auth, (int)data[0]);
2675 2676 2677 2678 2679 2680 2681 2682
       vnc_write_u32(vs, 1);
       if (vs->minor >= 8) {
           static const char err[] = "Authentication failed";
           vnc_write_u32(vs, sizeof(err));
           vnc_write(vs, err, sizeof(err));
       }
       vnc_client_error(vs);
    } else { /* Accept requested auth */
2683
       trace_vnc_auth_start(vs, vs->auth);
2684
       switch (vs->auth) {
2685
       case VNC_AUTH_NONE:
2686 2687 2688 2689
           if (vs->minor >= 8) {
               vnc_write_u32(vs, 0); /* Accept auth completion */
               vnc_flush(vs);
           }
2690
           trace_vnc_auth_pass(vs, vs->auth);
2691
           start_client_init(vs);
2692 2693 2694
           break;

       case VNC_AUTH_VNC:
2695 2696
           start_auth_vnc(vs);
           break;
2697

2698
       case VNC_AUTH_VENCRYPT:
2699 2700
           start_auth_vencrypt(vs);
           break;
2701

2702 2703 2704 2705 2706 2707
#ifdef CONFIG_VNC_SASL
       case VNC_AUTH_SASL:
           start_auth_sasl(vs);
           break;
#endif /* CONFIG_VNC_SASL */

2708
       default: /* Should not be possible, but just in case */
2709
           trace_vnc_auth_fail(vs, vs->auth, "Unhandled auth method", "");
2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721
           vnc_write_u8(vs, 1);
           if (vs->minor >= 8) {
               static const char err[] = "Authentication failed";
               vnc_write_u32(vs, sizeof(err));
               vnc_write(vs, err, sizeof(err));
           }
           vnc_client_error(vs);
       }
    }
    return 0;
}

T
ths 已提交
2722
static int protocol_version(VncState *vs, uint8_t *version, size_t len)
B
bellard 已提交
2723 2724 2725 2726 2727 2728
{
    char local[13];

    memcpy(local, version, 12);
    local[12] = 0;

2729
    if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
2730 2731 2732
        VNC_DEBUG("Malformed protocol version %s\n", local);
        vnc_client_error(vs);
        return 0;
B
bellard 已提交
2733
    }
2734 2735
    VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
    if (vs->major != 3 ||
2736 2737 2738 2739 2740 2741 2742 2743 2744 2745
        (vs->minor != 3 &&
         vs->minor != 4 &&
         vs->minor != 5 &&
         vs->minor != 7 &&
         vs->minor != 8)) {
        VNC_DEBUG("Unsupported client version\n");
        vnc_write_u32(vs, VNC_AUTH_INVALID);
        vnc_flush(vs);
        vnc_client_error(vs);
        return 0;
2746
    }
2747
    /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
2748 2749
     * as equivalent to v3.3 by servers
     */
2750
    if (vs->minor == 4 || vs->minor == 5)
2751
        vs->minor = 3;
2752 2753

    if (vs->minor == 3) {
2754
        trace_vnc_auth_start(vs, vs->auth);
2755 2756
        if (vs->auth == VNC_AUTH_NONE) {
            vnc_write_u32(vs, vs->auth);
2757
            vnc_flush(vs);
2758
            trace_vnc_auth_pass(vs, vs->auth);
2759
            start_client_init(vs);
2760
       } else if (vs->auth == VNC_AUTH_VNC) {
2761
            VNC_DEBUG("Tell client VNC auth\n");
2762
            vnc_write_u32(vs, vs->auth);
2763 2764 2765
            vnc_flush(vs);
            start_auth_vnc(vs);
       } else {
2766 2767
            trace_vnc_auth_fail(vs, vs->auth,
                                "Unsupported auth method for v3.3", "");
2768 2769 2770 2771 2772
            vnc_write_u32(vs, VNC_AUTH_INVALID);
            vnc_flush(vs);
            vnc_client_error(vs);
       }
    } else {
2773
        vnc_write_u8(vs, 1); /* num auth */
2774
        vnc_write_u8(vs, vs->auth);
2775 2776
        vnc_read_when(vs, protocol_client_auth, 1);
        vnc_flush(vs);
2777
    }
B
bellard 已提交
2778 2779 2780 2781

    return 0;
}

2782 2783 2784 2785 2786 2787 2788
static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
{
    struct VncSurface *vs = &vd->guest;

    return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
}

2789 2790 2791 2792 2793 2794 2795 2796 2797
void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
{
    int i, j;

    w = (x + w) / VNC_STAT_RECT;
    h = (y + h) / VNC_STAT_RECT;
    x /= VNC_STAT_RECT;
    y /= VNC_STAT_RECT;

C
Corentin Chary 已提交
2798 2799
    for (j = y; j <= h; j++) {
        for (i = x; i <= w; i++) {
2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811
            vs->lossy_rect[j][i] = 1;
        }
    }
}

static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
{
    VncState *vs;
    int sty = y / VNC_STAT_RECT;
    int stx = x / VNC_STAT_RECT;
    int has_dirty = 0;

M
Marc-André Lureau 已提交
2812 2813
    y = QEMU_ALIGN_DOWN(y, VNC_STAT_RECT);
    x = QEMU_ALIGN_DOWN(x, VNC_STAT_RECT);
2814 2815

    QTAILQ_FOREACH(vs, &vd->clients, next) {
2816
        int j;
2817 2818 2819 2820 2821 2822 2823 2824 2825

        /* kernel send buffers are full -> refresh later */
        if (vs->output.offset) {
            continue;
        }

        if (!vs->lossy_rect[sty][stx]) {
            continue;
        }
C
Corentin Chary 已提交
2826

2827 2828
        vs->lossy_rect[sty][stx] = 0;
        for (j = 0; j < VNC_STAT_RECT; ++j) {
2829 2830 2831
            bitmap_set(vs->dirty[y + j],
                       x / VNC_DIRTY_PIXELS_PER_BIT,
                       VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT);
2832 2833 2834
        }
        has_dirty++;
    }
C
Corentin Chary 已提交
2835

2836 2837 2838 2839
    return has_dirty;
}

static int vnc_update_stats(VncDisplay *vd,  struct timeval * tv)
2840
{
2841 2842 2843 2844
    int width = MIN(pixman_image_get_width(vd->guest.fb),
                    pixman_image_get_width(vd->server));
    int height = MIN(pixman_image_get_height(vd->guest.fb),
                     pixman_image_get_height(vd->server));
2845 2846
    int x, y;
    struct timeval res;
2847
    int has_dirty = 0;
2848

2849 2850
    for (y = 0; y < height; y += VNC_STAT_RECT) {
        for (x = 0; x < width; x += VNC_STAT_RECT) {
2851 2852 2853 2854 2855 2856
            VncRectStat *rect = vnc_stat_rect(vd, x, y);

            rect->updated = false;
        }
    }

B
Blue Swirl 已提交
2857
    qemu_timersub(tv, &VNC_REFRESH_STATS, &res);
2858 2859

    if (timercmp(&vd->guest.last_freq_check, &res, >)) {
2860
        return has_dirty;
2861 2862 2863
    }
    vd->guest.last_freq_check = *tv;

2864 2865
    for (y = 0; y < height; y += VNC_STAT_RECT) {
        for (x = 0; x < width; x += VNC_STAT_RECT) {
2866 2867 2868 2869 2870 2871 2872 2873 2874
            VncRectStat *rect= vnc_stat_rect(vd, x, y);
            int count = ARRAY_SIZE(rect->times);
            struct timeval min, max;

            if (!timerisset(&rect->times[count - 1])) {
                continue ;
            }

            max = rect->times[(rect->idx + count - 1) % count];
B
Blue Swirl 已提交
2875
            qemu_timersub(tv, &max, &res);
2876 2877 2878

            if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) {
                rect->freq = 0;
2879
                has_dirty += vnc_refresh_lossy_rect(vd, x, y);
2880 2881 2882 2883 2884 2885
                memset(rect->times, 0, sizeof (rect->times));
                continue ;
            }

            min = rect->times[rect->idx];
            max = rect->times[(rect->idx + count - 1) % count];
B
Blue Swirl 已提交
2886
            qemu_timersub(&max, &min, &res);
2887 2888 2889 2890 2891 2892

            rect->freq = res.tv_sec + res.tv_usec / 1000000.;
            rect->freq /= count;
            rect->freq = 1. / rect->freq;
        }
    }
2893
    return has_dirty;
2894 2895 2896 2897 2898 2899 2900 2901
}

double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
{
    int i, j;
    double total = 0;
    int num = 0;

M
Marc-André Lureau 已提交
2902 2903
    x =  QEMU_ALIGN_DOWN(x, VNC_STAT_RECT);
    y =  QEMU_ALIGN_DOWN(y, VNC_STAT_RECT);
2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931

    for (j = y; j <= y + h; j += VNC_STAT_RECT) {
        for (i = x; i <= x + w; i += VNC_STAT_RECT) {
            total += vnc_stat_rect(vs->vd, i, j)->freq;
            num++;
        }
    }

    if (num) {
        return total / num;
    } else {
        return 0;
    }
}

static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
{
    VncRectStat *rect;

    rect = vnc_stat_rect(vd, x, y);
    if (rect->updated) {
        return ;
    }
    rect->times[rect->idx] = *tv;
    rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times);
    rect->updated = true;
}

S
Stefano Stabellini 已提交
2932 2933
static int vnc_refresh_server_surface(VncDisplay *vd)
{
2934 2935 2936 2937
    int width = MIN(pixman_image_get_width(vd->guest.fb),
                    pixman_image_get_width(vd->server));
    int height = MIN(pixman_image_get_height(vd->guest.fb),
                     pixman_image_get_height(vd->server));
2938
    int cmp_bytes, server_stride, line_bytes, guest_ll, guest_stride, y = 0;
2939
    uint8_t *guest_row0 = NULL, *server_row0;
2940
    VncState *vs;
S
Stefano Stabellini 已提交
2941
    int has_dirty = 0;
2942
    pixman_image_t *tmpbuf = NULL;
S
Stefano Stabellini 已提交
2943

C
Corentin Chary 已提交
2944
    struct timeval tv = { 0, 0 };
2945

C
Corentin Chary 已提交
2946 2947 2948 2949
    if (!vd->non_adaptive) {
        gettimeofday(&tv, NULL);
        has_dirty = vnc_update_stats(vd, &tv);
    }
2950

S
Stefano Stabellini 已提交
2951 2952 2953 2954 2955
    /*
     * Walk through the guest dirty map.
     * Check and copy modified bits from guest to server surface.
     * Update server dirty map.
     */
2956
    server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
2957 2958
    server_stride = guest_stride = guest_ll =
        pixman_image_get_stride(vd->server);
2959 2960
    cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES,
                    server_stride);
2961 2962 2963
    if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
        int width = pixman_image_get_width(vd->server);
        tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
2964
    } else {
2965 2966
        int guest_bpp =
            PIXMAN_FORMAT_BPP(pixman_image_get_format(vd->guest.fb));
2967 2968
        guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
        guest_stride = pixman_image_get_stride(vd->guest.fb);
2969 2970
        guest_ll = pixman_image_get_width(vd->guest.fb)
                   * DIV_ROUND_UP(guest_bpp, 8);
2971
    }
2972
    line_bytes = MIN(server_stride, guest_ll);
2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985

    for (;;) {
        int x;
        uint8_t *guest_ptr, *server_ptr;
        unsigned long offset = find_next_bit((unsigned long *) &vd->guest.dirty,
                                             height * VNC_DIRTY_BPL(&vd->guest),
                                             y * VNC_DIRTY_BPL(&vd->guest));
        if (offset == height * VNC_DIRTY_BPL(&vd->guest)) {
            /* no more dirty bits */
            break;
        }
        y = offset / VNC_DIRTY_BPL(&vd->guest);
        x = offset % VNC_DIRTY_BPL(&vd->guest);
S
Stefano Stabellini 已提交
2986

2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998
        server_ptr = server_row0 + y * server_stride + x * cmp_bytes;

        if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
            qemu_pixman_linebuf_fill(tmpbuf, vd->guest.fb, width, 0, y);
            guest_ptr = (uint8_t *)pixman_image_get_data(tmpbuf);
        } else {
            guest_ptr = guest_row0 + y * guest_stride;
        }
        guest_ptr += x * cmp_bytes;

        for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT);
             x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
2999
            int _cmp_bytes = cmp_bytes;
3000 3001 3002
            if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
                continue;
            }
3003 3004
            if ((x + 1) * cmp_bytes > line_bytes) {
                _cmp_bytes = line_bytes - x * cmp_bytes;
3005
            }
3006
            assert(_cmp_bytes >= 0);
3007
            if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) {
3008 3009
                continue;
            }
3010
            memcpy(server_ptr, guest_ptr, _cmp_bytes);
3011 3012 3013
            if (!vd->non_adaptive) {
                vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
                                 y, &tv);
S
Stefano Stabellini 已提交
3014
            }
3015 3016 3017 3018
            QTAILQ_FOREACH(vs, &vd->clients, next) {
                set_bit(x, vs->dirty[y]);
            }
            has_dirty++;
S
Stefano Stabellini 已提交
3019
        }
3020 3021

        y++;
S
Stefano Stabellini 已提交
3022
    }
3023
    qemu_pixman_image_unref(tmpbuf);
S
Stefano Stabellini 已提交
3024 3025 3026
    return has_dirty;
}

G
Gerd Hoffmann 已提交
3027
static void vnc_refresh(DisplayChangeListener *dcl)
3028
{
G
Gerd Hoffmann 已提交
3029
    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
3030 3031
    VncState *vs, *vn;
    int has_dirty, rects = 0;
3032

3033 3034 3035 3036 3037
    if (QTAILQ_EMPTY(&vd->clients)) {
        update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX);
        return;
    }

3038
    graphic_hw_update(vd->dcl.con);
3039

C
Corentin Chary 已提交
3040
    if (vnc_trylock_display(vd)) {
G
Gerd Hoffmann 已提交
3041
        update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
C
Corentin Chary 已提交
3042 3043 3044
        return;
    }

S
Stefano Stabellini 已提交
3045
    has_dirty = vnc_refresh_server_surface(vd);
C
Corentin Chary 已提交
3046
    vnc_unlock_display(vd);
S
Stefano Stabellini 已提交
3047

3048
    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
3049
        rects += vnc_update_client(vs, has_dirty);
3050
        /* vs might be free()ed here */
3051
    }
C
Corentin Chary 已提交
3052

S
Stefano Stabellini 已提交
3053
    if (has_dirty && rects) {
G
Gerd Hoffmann 已提交
3054 3055 3056 3057
        vd->dcl.update_interval /= 2;
        if (vd->dcl.update_interval < VNC_REFRESH_INTERVAL_BASE) {
            vd->dcl.update_interval = VNC_REFRESH_INTERVAL_BASE;
        }
S
Stefano Stabellini 已提交
3058
    } else {
G
Gerd Hoffmann 已提交
3059 3060 3061 3062
        vd->dcl.update_interval += VNC_REFRESH_INTERVAL_INC;
        if (vd->dcl.update_interval > VNC_REFRESH_INTERVAL_MAX) {
            vd->dcl.update_interval = VNC_REFRESH_INTERVAL_MAX;
        }
3063 3064 3065
    }
}

3066
static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
3067
                        bool skipauth, bool websocket)
3068
{
3069
    VncState *vs = g_new0(VncState, 1);
3070
    bool first_client = QTAILQ_EMPTY(&vd->clients);
3071 3072
    int i;

3073
    trace_vnc_client_connect(vs, sioc);
3074
    vs->magic = VNC_MAGIC;
3075 3076 3077 3078
    vs->sioc = sioc;
    object_ref(OBJECT(vs->sioc));
    vs->ioc = QIO_CHANNEL(sioc);
    object_ref(OBJECT(vs->ioc));
G
Gerd Hoffmann 已提交
3079
    vs->vd = vd;
3080

3081 3082 3083
    buffer_init(&vs->input,          "vnc-input/%p", sioc);
    buffer_init(&vs->output,         "vnc-output/%p", sioc);
    buffer_init(&vs->jobs_buffer,    "vnc-jobs_buffer/%p", sioc);
G
Gerd Hoffmann 已提交
3084

3085 3086 3087
    buffer_init(&vs->tight.tight,    "vnc-tight/%p", sioc);
    buffer_init(&vs->tight.zlib,     "vnc-tight-zlib/%p", sioc);
    buffer_init(&vs->tight.gradient, "vnc-tight-gradient/%p", sioc);
G
Gerd Hoffmann 已提交
3088
#ifdef CONFIG_VNC_JPEG
3089
    buffer_init(&vs->tight.jpeg,     "vnc-tight-jpeg/%p", sioc);
G
Gerd Hoffmann 已提交
3090 3091
#endif
#ifdef CONFIG_VNC_PNG
3092
    buffer_init(&vs->tight.png,      "vnc-tight-png/%p", sioc);
G
Gerd Hoffmann 已提交
3093
#endif
3094 3095 3096 3097
    buffer_init(&vs->zlib.zlib,      "vnc-zlib/%p", sioc);
    buffer_init(&vs->zrle.zrle,      "vnc-zrle/%p", sioc);
    buffer_init(&vs->zrle.fb,        "vnc-zrle-fb/%p", sioc);
    buffer_init(&vs->zrle.zlib,      "vnc-zrle-zlib/%p", sioc);
G
Gerd Hoffmann 已提交
3098

3099 3100 3101 3102
    if (skipauth) {
	vs->auth = VNC_AUTH_NONE;
	vs->subauth = VNC_AUTH_INVALID;
    } else {
3103 3104 3105 3106 3107 3108 3109
        if (websocket) {
            vs->auth = vd->ws_auth;
            vs->subauth = VNC_AUTH_INVALID;
        } else {
            vs->auth = vd->auth;
            vs->subauth = vd->subauth;
        }
3110
    }
3111 3112
    VNC_DEBUG("Client sioc=%p ws=%d auth=%d subauth=%d\n",
              sioc, websocket, vs->auth, vs->subauth);
3113

3114
    vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
3115
    for (i = 0; i < VNC_STAT_ROWS; ++i) {
3116
        vs->lossy_rect[i] = g_new0(uint8_t, VNC_STAT_COLS);
3117
    }
3118

3119
    VNC_DEBUG("New client on socket %p\n", vs->sioc);
G
Gerd Hoffmann 已提交
3120
    update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
3121
    qio_channel_set_blocking(vs->ioc, false, NULL);
3122 3123 3124
    if (vs->ioc_tag) {
        g_source_remove(vs->ioc_tag);
    }
3125 3126
    if (websocket) {
        vs->websocket = 1;
3127
        if (vd->tlscreds) {
3128 3129
            vs->ioc_tag = qio_channel_add_watch(
                vs->ioc, G_IO_IN, vncws_tls_handshake_io, vs, NULL);
3130
        } else {
3131 3132
            vs->ioc_tag = qio_channel_add_watch(
                vs->ioc, G_IO_IN, vncws_handshake_io, vs, NULL);
T
Tim Hardeck 已提交
3133
        }
3134 3135 3136
    } else {
        vs->ioc_tag = qio_channel_add_watch(
            vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
3137
    }
3138

3139
    vnc_client_cache_addr(vs);
W
Wenchao Xia 已提交
3140
    vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED);
3141
    vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
3142

3143 3144 3145 3146 3147 3148 3149 3150
    vs->last_x = -1;
    vs->last_y = -1;

    vs->as.freq = 44100;
    vs->as.nchannels = 2;
    vs->as.fmt = AUD_FMT_S16;
    vs->as.endianness = 0;

C
Corentin Chary 已提交
3151
    qemu_mutex_init(&vs->output_mutex);
3152
    vs->bh = qemu_bh_new(vnc_jobs_bh, vs);
C
Corentin Chary 已提交
3153

G
Gerd Hoffmann 已提交
3154
    QTAILQ_INSERT_TAIL(&vd->clients, vs, next);
3155 3156 3157
    if (first_client) {
        vnc_update_server_surface(vd);
    }
S
Stefano Stabellini 已提交
3158

3159
    graphic_hw_update(vd->dcl.con);
S
Stefano Stabellini 已提交
3160

3161
    if (!vs->websocket) {
3162
        vnc_start_protocol(vs);
3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174
    }

    if (vd->num_connecting > vd->connections_limit) {
        QTAILQ_FOREACH(vs, &vd->clients, next) {
            if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) {
                vnc_disconnect_start(vs);
                return;
            }
        }
    }
}

3175
void vnc_start_protocol(VncState *vs)
3176
{
3177 3178 3179
    vnc_write(vs, "RFB 003.008\n", 12);
    vnc_flush(vs);
    vnc_read_when(vs, protocol_version, 12);
3180

3181 3182
    vs->mouse_mode_notifier.notify = check_pointer_type_change;
    qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
3183 3184
}

3185 3186 3187
static void vnc_listen_io(QIONetListener *listener,
                          QIOChannelSocket *cioc,
                          void *opaque)
B
bellard 已提交
3188
{
3189
    VncDisplay *vd = opaque;
3190
    bool isWebsock = listener == vd->wslistener;
3191

3192 3193 3194 3195
    qio_channel_set_name(QIO_CHANNEL(cioc),
                         isWebsock ? "vnc-ws-server" : "vnc-server");
    qio_channel_set_delay(QIO_CHANNEL(cioc), false);
    vnc_connect(vd, cioc, false, isWebsock);
3196 3197
}

3198
static const DisplayChangeListenerOps dcl_ops = {
3199 3200 3201 3202 3203 3204 3205
    .dpy_name             = "vnc",
    .dpy_refresh          = vnc_refresh,
    .dpy_gfx_update       = vnc_dpy_update,
    .dpy_gfx_switch       = vnc_dpy_switch,
    .dpy_gfx_check_format = qemu_pixman_check_format,
    .dpy_mouse_set        = vnc_mouse_set,
    .dpy_cursor_define    = vnc_dpy_cursor_define,
3206 3207
};

3208
void vnc_display_init(const char *id)
B
bellard 已提交
3209
{
3210
    VncDisplay *vd;
3211 3212 3213 3214

    if (vnc_display_find(id) != NULL) {
        return;
    }
3215
    vd = g_malloc0(sizeof(*vd));
B
bellard 已提交
3216

3217 3218
    vd->id = strdup(id);
    QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
B
bellard 已提交
3219

3220 3221
    QTAILQ_INIT(&vd->clients);
    vd->expires = TIME_MAX;
B
bellard 已提交
3222

3223 3224
    if (keyboard_layout) {
        trace_vnc_key_map_init(keyboard_layout);
3225
        vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
3226
    } else {
3227
        vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
3228
    }
B
bellard 已提交
3229

3230
    if (!vd->kbd_layout) {
3231
        exit(1);
3232
    }
B
bellard 已提交
3233

3234 3235
    vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
    vd->connections_limit = 32;
3236

3237
    qemu_mutex_init(&vd->mutex);
C
Corentin Chary 已提交
3238 3239
    vnc_start_worker_thread();

3240 3241
    vd->dcl.ops = &dcl_ops;
    register_displaychangelistener(&vd->dcl);
3242 3243
}

3244

3245
static void vnc_display_close(VncDisplay *vd)
3246
{
3247
    if (!vd) {
3248
        return;
3249 3250
    }
    vd->is_unix = false;
3251 3252 3253 3254

    if (vd->listener) {
        qio_net_listener_disconnect(vd->listener);
        object_unref(OBJECT(vd->listener));
3255
    }
3256
    vd->listener = NULL;
3257

3258 3259 3260
    if (vd->wslistener) {
        qio_net_listener_disconnect(vd->wslistener);
        object_unref(OBJECT(vd->wslistener));
3261
    }
3262
    vd->wslistener = NULL;
3263

3264 3265 3266 3267 3268
    vd->auth = VNC_AUTH_INVALID;
    vd->subauth = VNC_AUTH_INVALID;
    if (vd->tlscreds) {
        object_unparent(OBJECT(vd->tlscreds));
        vd->tlscreds = NULL;
3269
    }
3270 3271
    g_free(vd->tlsaclname);
    vd->tlsaclname = NULL;
P
Pierre Ossman 已提交
3272 3273
    if (vd->lock_key_sync) {
        qemu_remove_led_event_handler(vd->led);
G
Gerd Hoffmann 已提交
3274
        vd->led = NULL;
P
Pierre Ossman 已提交
3275
    }
3276 3277
}

3278
int vnc_display_password(const char *id, const char *password)
3279
{
3280
    VncDisplay *vd = vnc_display_find(id);
3281

3282
    if (!vd) {
3283
        return -EINVAL;
3284
    }
3285
    if (vd->auth == VNC_AUTH_NONE) {
3286
        error_printf_unless_qmp("If you want use passwords please enable "
3287
                                "password auth using '-vnc ${dpy},password'.\n");
3288
        return -EINVAL;
3289 3290
    }

3291 3292
    g_free(vd->password);
    vd->password = g_strdup(password);
3293 3294

    return 0;
3295 3296
}

3297
int vnc_display_pw_expire(const char *id, time_t expires)
G
Gerd Hoffmann 已提交
3298
{
3299
    VncDisplay *vd = vnc_display_find(id);
G
Gerd Hoffmann 已提交
3300

3301
    if (!vd) {
3302 3303 3304
        return -EINVAL;
    }

3305
    vd->expires = expires;
G
Gerd Hoffmann 已提交
3306 3307 3308
    return 0;
}

3309
static void vnc_display_print_local_addr(VncDisplay *vd)
3310
{
3311
    SocketAddress *addr;
3312
    Error *err = NULL;
G
Gerd Hoffmann 已提交
3313

3314
    if (!vd->listener || !vd->listener->nsioc) {
3315 3316 3317
        return;
    }

3318
    addr = qio_channel_socket_get_local_address(vd->listener->sioc[0], &err);
3319
    if (!addr) {
3320
        return;
3321 3322
    }

3323 3324
    if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
        qapi_free_SocketAddress(addr);
3325
        return;
3326
    }
3327
    error_printf_unless_qmp("VNC server running on %s:%s\n",
3328 3329 3330
                            addr->u.inet.host,
                            addr->u.inet.port);
    qapi_free_SocketAddress(addr);
3331 3332
}

3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344
static QemuOptsList qemu_vnc_opts = {
    .name = "vnc",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_vnc_opts.head),
    .implied_opt_name = "vnc",
    .desc = {
        {
            .name = "vnc",
            .type = QEMU_OPT_STRING,
        },{
            .name = "websocket",
            .type = QEMU_OPT_STRING,
        },{
3345 3346
            .name = "tls-creds",
            .type = QEMU_OPT_STRING,
3347 3348 3349
        },{
            .name = "share",
            .type = QEMU_OPT_STRING,
3350 3351 3352 3353 3354 3355
        },{
            .name = "display",
            .type = QEMU_OPT_STRING,
        },{
            .name = "head",
            .type = QEMU_OPT_NUMBER,
G
Gerd Hoffmann 已提交
3356 3357 3358
        },{
            .name = "connections",
            .type = QEMU_OPT_NUMBER,
3359 3360 3361 3362 3363 3364 3365 3366 3367
        },{
            .name = "to",
            .type = QEMU_OPT_NUMBER,
        },{
            .name = "ipv4",
            .type = QEMU_OPT_BOOL,
        },{
            .name = "ipv6",
            .type = QEMU_OPT_BOOL,
3368 3369 3370 3371 3372 3373 3374 3375 3376
        },{
            .name = "password",
            .type = QEMU_OPT_BOOL,
        },{
            .name = "reverse",
            .type = QEMU_OPT_BOOL,
        },{
            .name = "lock-key-sync",
            .type = QEMU_OPT_BOOL,
3377 3378 3379
        },{
            .name = "key-delay-ms",
            .type = QEMU_OPT_NUMBER,
3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396
        },{
            .name = "sasl",
            .type = QEMU_OPT_BOOL,
        },{
            .name = "acl",
            .type = QEMU_OPT_BOOL,
        },{
            .name = "lossy",
            .type = QEMU_OPT_BOOL,
        },{
            .name = "non-adaptive",
            .type = QEMU_OPT_BOOL,
        },
        { /* end of list */ }
    },
};

3397

3398
static int
3399 3400 3401
vnc_display_setup_auth(int *auth,
                       int *subauth,
                       QCryptoTLSCreds *tlscreds,
3402 3403
                       bool password,
                       bool sasl,
3404 3405
                       bool websocket,
                       Error **errp)
3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439
{
    /*
     * We have a choice of 3 authentication options
     *
     *   1. none
     *   2. vnc
     *   3. sasl
     *
     * The channel can be run in 2 modes
     *
     *   1. clear
     *   2. tls
     *
     * And TLS can use 2 types of credentials
     *
     *   1. anon
     *   2. x509
     *
     * We thus have 9 possible logical combinations
     *
     *   1. clear + none
     *   2. clear + vnc
     *   3. clear + sasl
     *   4. tls + anon + none
     *   5. tls + anon + vnc
     *   6. tls + anon + sasl
     *   7. tls + x509 + none
     *   8. tls + x509 + vnc
     *   9. tls + x509 + sasl
     *
     * These need to be mapped into the VNC auth schemes
     * in an appropriate manner. In regular VNC, all the
     * TLS options get mapped into VNC_AUTH_VENCRYPT
     * sub-auth types.
3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452
     *
     * In websockets, the https:// protocol already provides
     * TLS support, so there is no need to make use of the
     * VeNCrypt extension. Furthermore, websockets browser
     * clients could not use VeNCrypt even if they wanted to,
     * as they cannot control when the TLS handshake takes
     * place. Thus there is no option but to rely on https://,
     * meaning combinations 4->6 and 7->9 will be mapped to
     * VNC auth schemes in the same way as combos 1->3.
     *
     * Regardless of fact that we have a different mapping to
     * VNC auth mechs for plain VNC vs websockets VNC, the end
     * result has the same security characteristics.
3453
     */
3454 3455
    if (websocket || !tlscreds) {
        if (password) {
3456
            VNC_DEBUG("Initializing VNC server with password auth\n");
3457 3458 3459 3460
            *auth = VNC_AUTH_VNC;
        } else if (sasl) {
            VNC_DEBUG("Initializing VNC server with SASL auth\n");
            *auth = VNC_AUTH_SASL;
3461
        } else {
3462 3463
            VNC_DEBUG("Initializing VNC server with no auth\n");
            *auth = VNC_AUTH_NONE;
3464
        }
3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489
        *subauth = VNC_AUTH_INVALID;
    } else {
        bool is_x509 = object_dynamic_cast(OBJECT(tlscreds),
                                           TYPE_QCRYPTO_TLS_CREDS_X509) != NULL;
        bool is_anon = object_dynamic_cast(OBJECT(tlscreds),
                                           TYPE_QCRYPTO_TLS_CREDS_ANON) != NULL;

        if (!is_x509 && !is_anon) {
            error_setg(errp,
                       "Unsupported TLS cred type %s",
                       object_get_typename(OBJECT(tlscreds)));
            return -1;
        }
        *auth = VNC_AUTH_VENCRYPT;
        if (password) {
            if (is_x509) {
                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
                *subauth = VNC_AUTH_VENCRYPT_X509VNC;
            } else {
                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
                *subauth = VNC_AUTH_VENCRYPT_TLSVNC;
            }

        } else if (sasl) {
            if (is_x509) {
3490
                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
3491
                *subauth = VNC_AUTH_VENCRYPT_X509SASL;
3492
            } else {
3493 3494
                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
                *subauth = VNC_AUTH_VENCRYPT_TLSSASL;
3495 3496
            }
        } else {
3497
            if (is_x509) {
3498
                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
3499
                *subauth = VNC_AUTH_VENCRYPT_X509NONE;
3500
            } else {
3501 3502
                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
                *subauth = VNC_AUTH_VENCRYPT_TLSNONE;
3503
            }
3504
        }
3505
    }
3506 3507 3508 3509
    return 0;
}


3510 3511
static int vnc_display_get_address(const char *addrstr,
                                   bool websocket,
G
Gerd Hoffmann 已提交
3512
                                   bool reverse,
3513 3514 3515 3516 3517 3518
                                   int displaynum,
                                   int to,
                                   bool has_ipv4,
                                   bool has_ipv6,
                                   bool ipv4,
                                   bool ipv6,
3519
                                   SocketAddress **retaddr,
3520 3521 3522
                                   Error **errp)
{
    int ret = -1;
3523
    SocketAddress *addr = NULL;
3524

3525
    addr = g_new0(SocketAddress, 1);
3526 3527

    if (strncmp(addrstr, "unix:", 5) == 0) {
3528 3529
        addr->type = SOCKET_ADDRESS_TYPE_UNIX;
        addr->u.q_unix.path = g_strdup(addrstr + 5);
3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564

        if (websocket) {
            error_setg(errp, "UNIX sockets not supported with websock");
            goto cleanup;
        }

        if (to) {
            error_setg(errp, "Port range not support with UNIX socket");
            goto cleanup;
        }
        ret = 0;
    } else {
        const char *port;
        size_t hostlen;
        unsigned long long baseport = 0;
        InetSocketAddress *inet;

        port = strrchr(addrstr, ':');
        if (!port) {
            if (websocket) {
                hostlen = 0;
                port = addrstr;
            } else {
                error_setg(errp, "no vnc port specified");
                goto cleanup;
            }
        } else {
            hostlen = port - addrstr;
            port++;
            if (*port == '\0') {
                error_setg(errp, "vnc port cannot be empty");
                goto cleanup;
            }
        }

3565 3566
        addr->type = SOCKET_ADDRESS_TYPE_INET;
        inet = &addr->u.inet;
3567 3568 3569 3570 3571 3572 3573 3574 3575 3576
        if (addrstr[0] == '[' && addrstr[hostlen - 1] == ']') {
            inet->host = g_strndup(addrstr + 1, hostlen - 2);
        } else {
            inet->host = g_strndup(addrstr, hostlen);
        }
        /* plain VNC port is just an offset, for websocket
         * port is absolute */
        if (websocket) {
            if (g_str_equal(addrstr, "") ||
                g_str_equal(addrstr, "on")) {
3577 3578 3579 3580
                if (displaynum == -1) {
                    error_setg(errp, "explicit websocket port is required");
                    goto cleanup;
                }
3581 3582 3583 3584 3585 3586 3587 3588 3589 3590
                inet->port = g_strdup_printf(
                    "%d", displaynum + 5700);
                if (to) {
                    inet->has_to = true;
                    inet->to = to + 5700;
                }
            } else {
                inet->port = g_strdup(port);
            }
        } else {
G
Gerd Hoffmann 已提交
3591
            int offset = reverse ? 0 : 5900;
3592 3593 3594 3595 3596
            if (parse_uint_full(port, &baseport, 10) < 0) {
                error_setg(errp, "can't convert to a number: %s", port);
                goto cleanup;
            }
            if (baseport > 65535 ||
G
Gerd Hoffmann 已提交
3597
                baseport + offset > 65535) {
3598 3599 3600 3601
                error_setg(errp, "port %s out of range", port);
                goto cleanup;
            }
            inet->port = g_strdup_printf(
G
Gerd Hoffmann 已提交
3602
                "%d", (int)baseport + offset);
3603 3604 3605

            if (to) {
                inet->has_to = true;
G
Gerd Hoffmann 已提交
3606
                inet->to = to + offset;
3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621
            }
        }

        inet->ipv4 = ipv4;
        inet->has_ipv4 = has_ipv4;
        inet->ipv6 = ipv6;
        inet->has_ipv6 = has_ipv6;

        ret = baseport;
    }

    *retaddr = addr;

 cleanup:
    if (ret < 0) {
3622
        qapi_free_SocketAddress(addr);
3623 3624 3625 3626
    }
    return ret;
}

3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640
static void vnc_free_addresses(SocketAddress ***retsaddr,
                               size_t *retnsaddr)
{
    size_t i;

    for (i = 0; i < *retnsaddr; i++) {
        qapi_free_SocketAddress((*retsaddr)[i]);
    }
    g_free(*retsaddr);

    *retsaddr = NULL;
    *retnsaddr = 0;
}

3641
static int vnc_display_get_addresses(QemuOpts *opts,
G
Gerd Hoffmann 已提交
3642
                                     bool reverse,
3643
                                     SocketAddress ***retsaddr,
3644
                                     size_t *retnsaddr,
3645
                                     SocketAddress ***retwsaddr,
3646
                                     size_t *retnwsaddr,
3647 3648
                                     Error **errp)
{
3649 3650
    SocketAddress *saddr = NULL;
    SocketAddress *wsaddr = NULL;
3651 3652
    QemuOptsIter addriter;
    const char *addr;
3653 3654 3655 3656 3657
    int to = qemu_opt_get_number(opts, "to", 0);
    bool has_ipv4 = qemu_opt_get(opts, "ipv4");
    bool has_ipv6 = qemu_opt_get(opts, "ipv6");
    bool ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
    bool ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
3658 3659
    int displaynum = -1;
    int ret = -1;
3660

3661 3662 3663 3664
    *retsaddr = NULL;
    *retnsaddr = 0;
    *retwsaddr = NULL;
    *retnwsaddr = 0;
3665

3666 3667 3668 3669 3670 3671
    addr = qemu_opt_get(opts, "vnc");
    if (addr == NULL || g_str_equal(addr, "none")) {
        ret = 0;
        goto cleanup;
    }
    if (qemu_opt_get(opts, "websocket") &&
3672 3673 3674
        !qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
        error_setg(errp,
                   "SHA1 hash support is required for websockets");
3675 3676 3677 3678 3679 3680
        goto cleanup;
    }

    qemu_opt_iter_init(&addriter, opts, "vnc");
    while ((addr = qemu_opt_iter_next(&addriter)) != NULL) {
        int rv;
G
Gerd Hoffmann 已提交
3681
        rv = vnc_display_get_address(addr, false, reverse, 0, to,
3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693
                                     has_ipv4, has_ipv6,
                                     ipv4, ipv6,
                                     &saddr, errp);
        if (rv < 0) {
            goto cleanup;
        }
        /* Historical compat - first listen address can be used
         * to set the default websocket port
         */
        if (displaynum == -1) {
            displaynum = rv;
        }
3694
        *retsaddr = g_renew(SocketAddress *, *retsaddr, *retnsaddr + 1);
3695
        (*retsaddr)[(*retnsaddr)++] = saddr;
3696 3697
    }

3698 3699 3700 3701
    /* If we had multiple primary displays, we don't do defaults
     * for websocket, and require explicit config instead. */
    if (*retnsaddr > 1) {
        displaynum = -1;
3702
    }
3703 3704 3705

    qemu_opt_iter_init(&addriter, opts, "websocket");
    while ((addr = qemu_opt_iter_next(&addriter)) != NULL) {
G
Gerd Hoffmann 已提交
3706
        if (vnc_display_get_address(addr, true, reverse, displaynum, to,
3707 3708 3709
                                    has_ipv4, has_ipv6,
                                    ipv4, ipv6,
                                    &wsaddr, errp) < 0) {
3710
            goto cleanup;
3711
        }
3712 3713 3714 3715 3716 3717

        /* Historical compat - if only a single listen address was
         * provided, then this is used to set the default listen
         * address for websocket too
         */
        if (*retnsaddr == 1 &&
3718 3719 3720 3721 3722 3723
            (*retsaddr)[0]->type == SOCKET_ADDRESS_TYPE_INET &&
            wsaddr->type == SOCKET_ADDRESS_TYPE_INET &&
            g_str_equal(wsaddr->u.inet.host, "") &&
            !g_str_equal((*retsaddr)[0]->u.inet.host, "")) {
            g_free(wsaddr->u.inet.host);
            wsaddr->u.inet.host = g_strdup((*retsaddr)[0]->u.inet.host);
3724
        }
3725

3726
        *retwsaddr = g_renew(SocketAddress *, *retwsaddr, *retnwsaddr + 1);
3727
        (*retwsaddr)[(*retnwsaddr)++] = wsaddr;
3728 3729
    }

3730 3731 3732
    ret = 0;
 cleanup:
    if (ret < 0) {
3733 3734
        vnc_free_addresses(retsaddr, retnsaddr);
        vnc_free_addresses(retwsaddr, retnwsaddr);
3735 3736
    }
    return ret;
3737 3738
}

3739
static int vnc_display_connect(VncDisplay *vd,
3740
                               SocketAddress **saddr,
3741
                               size_t nsaddr,
3742
                               SocketAddress **wsaddr,
3743
                               size_t nwsaddr,
3744 3745 3746 3747
                               Error **errp)
{
    /* connect to viewer */
    QIOChannelSocket *sioc = NULL;
3748
    if (nwsaddr != 0) {
3749 3750 3751
        error_setg(errp, "Cannot use websockets in reverse mode");
        return -1;
    }
3752 3753 3754 3755
    if (nsaddr != 1) {
        error_setg(errp, "Expected a single address in reverse mode");
        return -1;
    }
3756 3757
    /* TODO SOCKET_ADDRESS_TYPE_FD when fd has AF_UNIX */
    vd->is_unix = saddr[0]->type == SOCKET_ADDRESS_TYPE_UNIX;
3758 3759
    sioc = qio_channel_socket_new();
    qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-reverse");
3760
    if (qio_channel_socket_connect_sync(sioc, saddr[0], errp) < 0) {
3761 3762 3763 3764 3765 3766 3767 3768 3769
        return -1;
    }
    vnc_connect(vd, sioc, false, false);
    object_unref(OBJECT(sioc));
    return 0;
}


static int vnc_display_listen(VncDisplay *vd,
3770
                              SocketAddress **saddr,
3771
                              size_t nsaddr,
3772
                              SocketAddress **wsaddr,
3773
                              size_t nwsaddr,
3774 3775
                              Error **errp)
{
3776
    size_t i;
3777

3778 3779 3780 3781 3782 3783 3784 3785 3786
    if (nsaddr) {
        vd->listener = qio_net_listener_new();
        qio_net_listener_set_name(vd->listener, "vnc-listen");
        for (i = 0; i < nsaddr; i++) {
            if (qio_net_listener_open_sync(vd->listener,
                                           saddr[i],
                                           errp) < 0)  {
                return -1;
            }
3787
        }
3788 3789 3790

        qio_net_listener_set_client_func(vd->listener,
                                         vnc_listen_io, vd, NULL);
3791
    }
3792 3793 3794 3795 3796 3797 3798 3799 3800 3801

    if (nwsaddr) {
        vd->wslistener = qio_net_listener_new();
        qio_net_listener_set_name(vd->wslistener, "vnc-ws-listen");
        for (i = 0; i < nwsaddr; i++) {
            if (qio_net_listener_open_sync(vd->wslistener,
                                           wsaddr[i],
                                           errp) < 0)  {
                return -1;
            }
3802
        }
3803 3804 3805

        qio_net_listener_set_client_func(vd->wslistener,
                                         vnc_listen_io, vd, NULL);
3806 3807 3808 3809 3810 3811
    }

    return 0;
}


3812
void vnc_display_open(const char *id, Error **errp)
3813
{
3814
    VncDisplay *vd = vnc_display_find(id);
3815
    QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
3816
    SocketAddress **saddr = NULL, **wsaddr = NULL;
3817
    size_t nsaddr, nwsaddr;
3818
    const char *share, *device_id;
3819
    QemuConsole *con;
3820 3821
    bool password = false;
    bool reverse = false;
3822
    const char *credid;
3823
    bool sasl = false;
3824
#ifdef CONFIG_VNC_SASL
3825 3826
    int saslErr;
#endif
3827
    int acl = 0;
G
Gerd Hoffmann 已提交
3828
    int lock_key_sync = 1;
3829
    int key_delay_ms;
3830

3831
    if (!vd) {
3832 3833 3834
        error_setg(errp, "VNC display not active");
        return;
    }
3835
    vnc_display_close(vd);
B
bellard 已提交
3836

3837 3838 3839
    if (!opts) {
        return;
    }
J
Ján Tomko 已提交
3840

G
Gerd Hoffmann 已提交
3841 3842
    reverse = qemu_opt_get_bool(opts, "reverse", false);
    if (vnc_display_get_addresses(opts, reverse, &saddr, &nsaddr,
3843
                                  &wsaddr, &nwsaddr, errp) < 0) {
G
Gerd Hoffmann 已提交
3844
        goto fail;
3845
    }
G
Gerd Hoffmann 已提交
3846

3847
    password = qemu_opt_get_bool(opts, "password", false);
3848 3849 3850 3851 3852 3853 3854 3855 3856
    if (password) {
        if (fips_get_state()) {
            error_setg(errp,
                       "VNC password auth disabled due to FIPS mode, "
                       "consider using the VeNCrypt or SASL authentication "
                       "methods as an alternative");
            goto fail;
        }
        if (!qcrypto_cipher_supports(
3857
                QCRYPTO_CIPHER_ALG_DES_RFB, QCRYPTO_CIPHER_MODE_ECB)) {
3858 3859 3860 3861
            error_setg(errp,
                       "Cipher backend does not support DES RFB algorithm");
            goto fail;
        }
3862 3863 3864
    }

    lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true);
3865
    key_delay_ms = qemu_opt_get_number(opts, "key-delay-ms", 10);
3866
    sasl = qemu_opt_get_bool(opts, "sasl", false);
3867 3868 3869 3870 3871 3872
#ifndef CONFIG_VNC_SASL
    if (sasl) {
        error_setg(errp, "VNC SASL auth requires cyrus-sasl support");
        goto fail;
    }
#endif /* CONFIG_VNC_SASL */
3873 3874 3875 3876 3877 3878 3879 3880 3881 3882
    credid = qemu_opt_get(opts, "tls-creds");
    if (credid) {
        Object *creds;
        creds = object_resolve_path_component(
            object_get_objects_root(), credid);
        if (!creds) {
            error_setg(errp, "No TLS credentials with id '%s'",
                       credid);
            goto fail;
        }
3883
        vd->tlscreds = (QCryptoTLSCreds *)
3884 3885
            object_dynamic_cast(creds,
                                TYPE_QCRYPTO_TLS_CREDS);
3886
        if (!vd->tlscreds) {
3887 3888 3889 3890
            error_setg(errp, "Object with id '%s' is not TLS credentials",
                       credid);
            goto fail;
        }
3891
        object_ref(OBJECT(vd->tlscreds));
3892

3893
        if (vd->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
3894 3895 3896 3897
            error_setg(errp,
                       "Expecting TLS credentials with a server endpoint");
            goto fail;
        }
3898 3899 3900 3901 3902 3903
    }
    acl = qemu_opt_get_bool(opts, "acl", false);

    share = qemu_opt_get(opts, "share");
    if (share) {
        if (strcmp(share, "ignore") == 0) {
3904
            vd->share_policy = VNC_SHARE_POLICY_IGNORE;
3905
        } else if (strcmp(share, "allow-exclusive") == 0) {
3906
            vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
3907
        } else if (strcmp(share, "force-shared") == 0) {
3908
            vd->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
3909 3910 3911 3912 3913
        } else {
            error_setg(errp, "unknown vnc share= option");
            goto fail;
        }
    } else {
3914
        vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
3915
    }
3916
    vd->connections_limit = qemu_opt_get_number(opts, "connections", 32);
3917 3918

#ifdef CONFIG_VNC_JPEG
3919
    vd->lossy = qemu_opt_get_bool(opts, "lossy", false);
3920
#endif
3921
    vd->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false);
3922 3923 3924
    /* adaptive updates are only used with tight encoding and
     * if lossy updates are enabled so we can disable all the
     * calculations otherwise */
3925 3926
    if (!vd->lossy) {
        vd->non_adaptive = true;
3927 3928
    }

3929
    if (acl) {
3930 3931
        if (strcmp(vd->id, "default") == 0) {
            vd->tlsaclname = g_strdup("vnc.x509dname");
G
Gerd Hoffmann 已提交
3932
        } else {
3933
            vd->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vd->id);
G
Gerd Hoffmann 已提交
3934
        }
3935
        qemu_acl_init(vd->tlsaclname);
3936
    }
3937 3938
#ifdef CONFIG_VNC_SASL
    if (acl && sasl) {
G
Gerd Hoffmann 已提交
3939 3940
        char *aclname;

3941
        if (strcmp(vd->id, "default") == 0) {
G
Gerd Hoffmann 已提交
3942 3943
            aclname = g_strdup("vnc.username");
        } else {
3944
            aclname = g_strdup_printf("vnc.%s.username", vd->id);
G
Gerd Hoffmann 已提交
3945
        }
3946
        vd->sasl.acl = qemu_acl_init(aclname);
G
Gerd Hoffmann 已提交
3947
        g_free(aclname);
3948 3949 3950
    }
#endif

3951 3952 3953 3954 3955
    if (vnc_display_setup_auth(&vd->auth, &vd->subauth,
                               vd->tlscreds, password,
                               sasl, false, errp) < 0) {
        goto fail;
    }
3956
    trace_vnc_auth_init(vd, 0, vd->auth, vd->subauth);
3957 3958 3959 3960

    if (vnc_display_setup_auth(&vd->ws_auth, &vd->ws_subauth,
                               vd->tlscreds, password,
                               sasl, true, errp) < 0) {
3961 3962
        goto fail;
    }
3963
    trace_vnc_auth_init(vd, 1, vd->ws_auth, vd->ws_subauth);
B
bellard 已提交
3964

3965 3966
#ifdef CONFIG_VNC_SASL
    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
3967 3968
        error_setg(errp, "Failed to initialize SASL auth: %s",
                   sasl_errstring(saslErr, NULL, NULL));
3969
        goto fail;
3970 3971
    }
#endif
3972
    vd->lock_key_sync = lock_key_sync;
P
Pierre Ossman 已提交
3973 3974 3975 3976
    if (lock_key_sync) {
        vd->led = qemu_add_led_event_handler(kbd_leds, vd);
    }
    vd->ledstate = 0;
3977
    vd->key_delay_ms = key_delay_ms;
3978

3979 3980 3981
    device_id = qemu_opt_get(opts, "display");
    if (device_id) {
        int head = qemu_opt_get_number(opts, "head", 0);
3982
        Error *err = NULL;
3983

3984 3985 3986
        con = qemu_console_lookup_by_device_name(device_id, head, &err);
        if (err) {
            error_propagate(errp, err);
3987 3988 3989 3990 3991 3992
            goto fail;
        }
    } else {
        con = NULL;
    }

3993 3994 3995 3996
    if (con != vd->dcl.con) {
        unregister_displaychangelistener(&vd->dcl);
        vd->dcl.con = con;
        register_displaychangelistener(&vd->dcl);
3997 3998
    }

3999 4000 4001 4002
    if (saddr == NULL) {
        goto cleanup;
    }

4003
    if (reverse) {
4004
        if (vnc_display_connect(vd, saddr, nsaddr, wsaddr, nwsaddr, errp) < 0) {
4005 4006
            goto fail;
        }
4007
    } else {
4008
        if (vnc_display_listen(vd, saddr, nsaddr, wsaddr, nwsaddr, errp) < 0) {
4009 4010
            goto fail;
        }
B
bellard 已提交
4011
    }
4012

4013
    if (qemu_opt_get(opts, "to")) {
4014
        vnc_display_print_local_addr(vd);
4015 4016
    }

4017
 cleanup:
4018 4019
    vnc_free_addresses(&saddr, &nsaddr);
    vnc_free_addresses(&wsaddr, &nwsaddr);
4020
    return;
4021 4022

fail:
4023
    vnc_display_close(vd);
4024
    goto cleanup;
B
bellard 已提交
4025
}
4026

4027
void vnc_display_add_client(const char *id, int csock, bool skipauth)
4028
{
4029
    VncDisplay *vd = vnc_display_find(id);
4030
    QIOChannelSocket *sioc;
4031

4032
    if (!vd) {
G
Gerd Hoffmann 已提交
4033 4034
        return;
    }
4035 4036 4037

    sioc = qio_channel_socket_new_fd(csock, NULL);
    if (sioc) {
4038
        qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-server");
4039
        vnc_connect(vd, sioc, skipauth, false);
4040 4041
        object_unref(OBJECT(sioc));
    }
4042
}
4043

4044
static void vnc_auto_assign_id(QemuOptsList *olist, QemuOpts *opts)
4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056
{
    int i = 2;
    char *id;

    id = g_strdup("default");
    while (qemu_opts_find(olist, id)) {
        g_free(id);
        id = g_strdup_printf("vnc%d", i++);
    }
    qemu_opts_set_id(opts, id);
}

4057
QemuOpts *vnc_parse(const char *str, Error **errp)
4058 4059
{
    QemuOptsList *olist = qemu_find_opts("vnc");
4060
    QemuOpts *opts = qemu_opts_parse(olist, str, true, errp);
4061
    const char *id;
4062

4063 4064 4065 4066 4067
    if (!opts) {
        return NULL;
    }

    id = qemu_opts_id(opts);
4068 4069
    if (!id) {
        /* auto-assign id if not present */
4070
        vnc_auto_assign_id(olist, opts);
4071
    }
4072 4073 4074
    return opts;
}

4075
int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
4076 4077 4078
{
    Error *local_err = NULL;
    char *id = (char *)qemu_opts_id(opts);
4079

4080
    assert(id);
4081 4082 4083
    vnc_display_init(id);
    vnc_display_open(id, &local_err);
    if (local_err != NULL) {
4084
        error_reportf_err(local_err, "Failed to start VNC server: ");
4085 4086 4087 4088 4089 4090 4091 4092 4093
        exit(1);
    }
    return 0;
}

static void vnc_register_config(void)
{
    qemu_add_opts(&qemu_vnc_opts);
}
4094
opts_init(vnc_register_config);