18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * QEMU VNC display driver
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (C) 2006 Fabrice Bellard
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (C) 2009 Red Hat, Inc
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Permission is hereby granted, free of charge, to any person obtaining a copy
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * of this software and associated documentation files (the "Software"), to deal
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * in the Software without restriction, including without limitation the rights
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * copies of the Software, and to permit persons to whom the Software is
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * furnished to do so, subject to the following conditions:
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The above copyright notice and this permission notice shall be included in
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * all copies or substantial portions of the Software.
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE.
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "vnc.h"
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "sysemu.h"
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu_socket.h"
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-timer.h"
315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "acl.h"
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define VNC_REFRESH_INTERVAL (1000 / 30)
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "vnc_keysym.h"
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "d3des.h"
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define count_bits(c, v) { \
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (c = 0; v; v >>= 1) \
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    { \
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        c += v & 1; \
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } \
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic VncDisplay *vnc_display; /* needed for info vnc */
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic DisplayChangeListener *dcl;
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic char *addr_to_string(const char *format,
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            struct sockaddr_storage *sa,
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            socklen_t salen) {
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *addr;
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char host[NI_MAXHOST];
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char serv[NI_MAXSERV];
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int err;
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size_t addrlen;
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((err = getnameinfo((struct sockaddr *)sa, salen,
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           host, sizeof(host),
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           serv, sizeof(serv),
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("Cannot resolve address %d: %s\n",
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                  err, gai_strerror(err));
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Enough for the existing format + the 2 vars we're
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * substituting in. */
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addrlen = strlen(format) + strlen(host) + strlen(serv);
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr = qemu_malloc(addrlen + 1);
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(addr, addrlen, format, host, serv);
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr[addrlen] = '\0';
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return addr;
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerchar *vnc_socket_local_addr(const char *format, int fd) {
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_storage sa;
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socklen_t salen;
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    salen = sizeof(sa);
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return addr_to_string(format, &sa, salen);
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerchar *vnc_socket_remote_addr(const char *format, int fd) {
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_storage sa;
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socklen_t salen;
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    salen = sizeof(sa);
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return addr_to_string(format, &sa, salen);
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char *vnc_auth_name(VncDisplay *vd) {
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch (vd->auth) {
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_INVALID:
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "invalid";
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_NONE:
1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "none";
1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_VNC:
1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "vnc";
1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_RA2:
1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "ra2";
1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_RA2NE:
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "ra2ne";
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_TIGHT:
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "tight";
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_ULTRA:
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "ultra";
1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_TLS:
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "tls";
1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_VENCRYPT:
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch (vd->subauth) {
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_AUTH_VENCRYPT_PLAIN:
1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt+plain";
1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_AUTH_VENCRYPT_TLSNONE:
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt+tls+none";
1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_AUTH_VENCRYPT_TLSVNC:
1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt+tls+vnc";
1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_AUTH_VENCRYPT_TLSPLAIN:
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt+tls+plain";
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_AUTH_VENCRYPT_X509NONE:
1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt+x509+none";
1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_AUTH_VENCRYPT_X509VNC:
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt+x509+vnc";
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_AUTH_VENCRYPT_X509PLAIN:
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt+x509+plain";
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_AUTH_VENCRYPT_TLSSASL:
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt+tls+sasl";
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_AUTH_VENCRYPT_X509SASL:
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt+x509+sasl";
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        default:
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return "vencrypt";
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "vencrypt";
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case VNC_AUTH_SASL:
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return "sasl";
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return "unknown";
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void do_info_vnc_client(Monitor *mon, VncState *client)
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *clientAddr =
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_socket_remote_addr("     address: %s:%s\n",
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               client->csock);
1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!clientAddr)
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, "Client:\n");
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, "%s", clientAddr);
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    free(clientAddr);
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (client->tls.session &&
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        client->tls.dname)
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "  x509 dname: %s\n", client->tls.dname);
1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "  x509 dname: none\n");
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (client->sasl.conn &&
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        client->sasl.username)
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "    username: %s\n", client->sasl.username);
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "    username: none\n");
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_info_vnc(Monitor *mon)
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vnc_display == NULL || vnc_display->display == NULL) {
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "Server: disabled\n");
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char *serverAddr = vnc_socket_local_addr("     address: %s:%s\n",
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                                 vnc_display->lsock);
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!serverAddr)
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return;
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "Server:\n");
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "%s", serverAddr);
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        free(serverAddr);
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "        auth: %s\n", vnc_auth_name(vnc_display));
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vnc_display->clients) {
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            VncState *client = vnc_display->clients;
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            while (client) {
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                do_info_vnc_client(mon, client);
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                client = client->next;
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            monitor_printf(mon, "Client: none\n");
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline uint32_t vnc_has_feature(VncState *vs, int feature) {
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return (vs->features & (1 << feature));
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TODO
2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   1) Get the queue working for IO.
2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   2) there is some weirdness when using the -S option (the screen is grey
2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project      and not totally invalidated
2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   3) resolutions > 1024
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void vnc_update_client(void *opaque);
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_disconnect_start(VncState *vs);
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_disconnect_finish(VncState *vs);
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_colordepth(VncState *vs);
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void vnc_set_bit(uint32_t *d, int k)
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d[k >> 5] |= 1 << (k & 0x1f);
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void vnc_clear_bit(uint32_t *d, int k)
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    d[k >> 5] &= ~(1 << (k & 0x1f));
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void vnc_set_bits(uint32_t *d, int n, int nb_words)
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int j;
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    j = 0;
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (n >= 32) {
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d[j++] = -1;
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        n -= 32;
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (n > 0)
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d[j++] = (1 << n) - 1;
2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (j < nb_words)
2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        d[j++] = 0;
2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int vnc_get_bit(const uint32_t *d, int k)
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (d[k >> 5] >> (k & 0x1f)) & 1;
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                               int nb_words)
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i = 0; i < nb_words; i++) {
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ((d1[i] & d2[i]) != 0)
2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 1;
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_update(VncState *vs, int x, int y, int w, int h)
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct VncSurface *s = &vs->guest;
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    h += y;
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* round x down to ensure the loop only spans one 16-pixel block per,
2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       iteration.  otherwise, if (x % 16) != 0, the last iteration may span
2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       two 16-pixel blocks but we only mark the first as dirty
2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    */
2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    w += (x % 16);
2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    x -= (x % 16);
2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    x = MIN(x, s->ds->width);
2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    y = MIN(y, s->ds->height);
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    w = MIN(x + w, s->ds->width) - x;
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    h = MIN(h, s->ds->height);
2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (; y < h; y++)
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (i = 0; i < w; i += 16)
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_set_bit(s->dirty[y], (x + i) / 16);
2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncDisplay *vd = ds->opaque;
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncState *vs = vd->clients;
2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (vs != NULL) {
2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_update(vs, x, y, w, h);
2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs = vs->next;
2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   int32_t encoding)
3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u16(vs, x);
3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u16(vs, y);
3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u16(vs, w);
3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u16(vs, h);
3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_s32(vs, encoding);
3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid buffer_reserve(Buffer *buffer, size_t len)
3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((buffer->capacity - buffer->offset) < len) {
3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        buffer->capacity += (len + 1024);
3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (buffer->buffer == NULL) {
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr, "vnc: out of memory\n");
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            exit(1);
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint buffer_empty(Buffer *buffer)
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return buffer->offset == 0;
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint8_t *buffer_end(Buffer *buffer)
3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return buffer->buffer + buffer->offset;
3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid buffer_reset(Buffer *buffer)
3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        buffer->offset = 0;
3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid buffer_append(Buffer *buffer, const void *data, size_t len)
3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memcpy(buffer->buffer + buffer->offset, data, len);
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    buffer->offset += len;
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_resize(VncState *vs)
3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DisplayState *ds = vs->ds;
3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int size_changed;
3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* guest surface */
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!vs->guest.ds)
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->guest.ds = qemu_mallocz(sizeof(*vs->guest.ds));
3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ds_get_bytes_per_pixel(ds) != vs->guest.ds->pf.bytes_per_pixel)
3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        console_color_init(ds);
3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_colordepth(vs);
3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size_changed = ds_get_width(ds) != vs->guest.ds->width ||
3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                   ds_get_height(ds) != vs->guest.ds->height;
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *(vs->guest.ds) = *(ds->surface);
3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (size_changed) {
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_write_u8(vs, 0);  /* msg id */
3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_write_u8(vs, 0);
3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_write_u16(vs, 1); /* number of rects */
3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   VNC_ENCODING_DESKTOPRESIZE);
3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_flush(vs);
3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memset(vs->guest.dirty, 0xFF, sizeof(vs->guest.dirty));
3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* server surface */
3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!vs->server.ds)
3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->server.ds = qemu_mallocz(sizeof(*vs->server.ds));
3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->server.ds->data)
3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(vs->server.ds->data);
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *(vs->server.ds) = *(ds->surface);
3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->server.ds->data = qemu_mallocz(vs->server.ds->linesize *
3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       vs->server.ds->height);
3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memset(vs->server.dirty, 0xFF, sizeof(vs->guest.dirty));
3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_dpy_resize(DisplayState *ds)
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncDisplay *vd = ds->opaque;
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncState *vs = vd->clients;
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (vs != NULL) {
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_resize(vs);
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs = vs->next;
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* fastest code */
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write(vs, pixels, size);
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* slowest but generic code. */
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t r, g, b;
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    r = ((((v & vs->server.ds->pf.rmask) >> vs->server.ds->pf.rshift) << vs->clientds.pf.rbits) >>
4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->server.ds->pf.rbits);
4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    g = ((((v & vs->server.ds->pf.gmask) >> vs->server.ds->pf.gshift) << vs->clientds.pf.gbits) >>
4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->server.ds->pf.gbits);
4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    b = ((((v & vs->server.ds->pf.bmask) >> vs->server.ds->pf.bshift) << vs->clientds.pf.bbits) >>
4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->server.ds->pf.bbits);
4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    v = (r << vs->clientds.pf.rshift) |
4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (g << vs->clientds.pf.gshift) |
4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (b << vs->clientds.pf.bshift);
4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(vs->clientds.pf.bytes_per_pixel) {
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 1:
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        buf[0] = v;
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 2:
4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[0] = v >> 8;
4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[1] = v;
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[1] = v >> 8;
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[0] = v;
4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 4:
4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[0] = v >> 24;
4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[1] = v >> 16;
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[2] = v >> 8;
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[3] = v;
4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[3] = v >> 24;
4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[2] = v >> 16;
4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[1] = v >> 8;
4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            buf[0] = v;
4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t buf[4];
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->server.ds->pf.bytes_per_pixel == 4) {
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint32_t *pixels = pixels1;
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int n, i;
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        n = size >> 2;
4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for(i = 0; i < n; i++) {
4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_convert_pixel(vs, buf, pixels[i]);
4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (vs->server.ds->pf.bytes_per_pixel == 2) {
4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint16_t *pixels = pixels1;
4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int n, i;
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        n = size >> 1;
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for(i = 0; i < n; i++) {
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_convert_pixel(vs, buf, pixels[i]);
4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (vs->server.ds->pf.bytes_per_pixel == 1) {
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint8_t *pixels = pixels1;
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int n, i;
4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        n = size;
4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for(i = 0; i < n; i++) {
4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_convert_pixel(vs, buf, pixels[i]);
4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t *row;
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    row = vs->server.ds->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < h; i++) {
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        row += ds_get_linesize(vs->ds);
4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F);
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define BPP 8
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "vnchextile.h"
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef BPP
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define BPP 16
4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "vnchextile.h"
4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef BPP
4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define BPP 32
5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "vnchextile.h"
5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef BPP
5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GENERIC
5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define BPP 8
5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "vnchextile.h"
5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef BPP
5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef GENERIC
5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GENERIC
5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define BPP 16
5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "vnchextile.h"
5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef BPP
5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef GENERIC
5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GENERIC
5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define BPP 32
5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "vnchextile.h"
5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef BPP
5198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#undef GENERIC
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, j;
5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int has_fg, has_bg;
5258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t *last_fg, *last_bg;
5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    last_fg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    last_bg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    has_fg = has_bg = 0;
5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (j = y; j < (y + h); j += 16) {
5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (i = x; i < (x + w); i += 16) {
5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vs->send_hextile_tile(vs, i, j,
5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                  MIN(16, x + w - i), MIN(16, y + h - j),
5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                  last_bg, last_fg, &has_bg, &has_fg);
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    free(last_fg);
5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    free(last_bg);
5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_zlib_init(VncState *vs)
5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i=0; i<(sizeof(vs->zlib_stream) / sizeof(z_stream)); i++)
5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->zlib_stream[i].opaque = NULL;
5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_zlib_start(VncState *vs)
5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    buffer_reset(&vs->zlib);
5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // make the output buffer be the zlib buffer, so we can compress it later
5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->zlib_tmp = vs->output;
5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->output = vs->zlib;
5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int vnc_zlib_stop(VncState *vs, int stream_id)
5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    z_streamp zstream = &vs->zlib_stream[stream_id];
5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int previous_out;
5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // switch back to normal output/zlib buffers
5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->zlib = vs->output;
5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->output = vs->zlib_tmp;
5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // compress the zlib buffer
5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // initialize the stream
5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // XXX need one stream per session
5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (zstream->opaque != vs) {
5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int err;
5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("VNC: initializing zlib stream %d\n", stream_id);
5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        zstream->zalloc = Z_NULL;
5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        zstream->zfree = Z_NULL;
5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
5815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (err != Z_OK) {
5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr, "VNC: error initializing zlib\n");
5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -1;
5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        zstream->opaque = vs;
5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // XXX what to do if tight_compression changed in between?
5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // reserve memory in output buffer
5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    buffer_reserve(&vs->output, vs->zlib.offset + 64);
5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // set pointers
5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    zstream->next_in = vs->zlib.buffer;
5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    zstream->avail_in = vs->zlib.offset;
5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    zstream->next_out = vs->output.buffer + vs->output.offset;
5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    zstream->avail_out = vs->output.capacity - vs->output.offset;
6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    zstream->data_type = Z_BINARY;
6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    previous_out = zstream->total_out;
6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // start encoding
6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) {
6055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "VNC: error during zlib compression\n");
6065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->output.offset = vs->output.capacity - zstream->avail_out;
6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return zstream->total_out - previous_out;
6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void send_framebuffer_update_zlib(VncState *vs, int x, int y, int w, int h)
6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int old_offset, new_offset, bytes_written;
6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_ZLIB);
6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // remember where we put in the follow-up size
6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    old_offset = vs->output.offset;
6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_s32(vs, 0);
6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // compress the stream
6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_zlib_start(vs);
6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    send_framebuffer_update_raw(vs, x, y, w, h);
6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    bytes_written = vnc_zlib_stop(vs, 0);
6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (bytes_written == -1)
6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // hack in the size
6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    new_offset = vs->output.offset;
6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->output.offset = old_offset;
6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u32(vs, bytes_written);
6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->output.offset = new_offset;
6365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
6395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(vs->vnc_encoding) {
6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_ZLIB:
6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            send_framebuffer_update_zlib(vs, x, y, w, h);
6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_HEXTILE:
6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            send_framebuffer_update_hextile(vs, x, y, w, h);
6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        default:
6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            send_framebuffer_update_raw(vs, x, y, w, h);
6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u8(vs, 0);  /* msg id */
6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u8(vs, 0);
6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u16(vs, 1); /* number of rects */
6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u16(vs, src_x);
6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u16(vs, src_y);
6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_flush(vs);
6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncDisplay *vd = ds->opaque;
6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncState *vs, *vn;
6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (vs = vd->clients; vs != NULL; vs = vn) {
6725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vn = vs->next;
6735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
6745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->force_update = 1;
6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_update_client(vs);
6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* vs might be free()ed here */
6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (vs = vd->clients; vs != NULL; vs = vs->next) {
6815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
6825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        else /* TODO */
6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_update(vs, dst_x, dst_y, w, h);
6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int find_and_clear_dirty_height(struct VncSurface *s,
6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       int y, int last_x, int x)
6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int h;
6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (h = 1; h < (s->ds->height - y); h++) {
6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int tmp_x;
6955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!vnc_get_bit(s->dirty[y + h], last_x))
6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (tmp_x = last_x; tmp_x < x; tmp_x++)
6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_clear_bit(s->dirty[y + h], tmp_x);
6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return h;
7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void vnc_update_client(void *opaque)
7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    VncState *vs = opaque;
7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->need_update && vs->csock != -1) {
7085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int y;
7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint8_t *guest_row;
7105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint8_t *server_row;
7115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int cmp_bytes;
7125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint32_t width_mask[VNC_DIRTY_WORDS];
7135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int n_rectangles;
7145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int saved_offset;
7155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int has_dirty = 0;
7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->output.offset && !vs->audio_cap && !vs->force_update) {
7185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* kernel send buffers are full -> drop frames to throttle */
7195973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner            qemu_mod_timer(vs->timer, qemu_get_clock_ms(rt_clock) + VNC_REFRESH_INTERVAL);
7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return;
7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vga_hw_update();
7248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /*
7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * Walk through the guest dirty map.
7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * Check and copy modified bits from guest to server surface.
7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * Update server dirty map.
7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         */
7305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_set_bits(width_mask, (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        cmp_bytes = 16 * ds_get_bytes_per_pixel(vs->ds);
7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        guest_row  = vs->guest.ds->data;
7335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        server_row = vs->server.ds->data;
7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (y = 0; y < vs->guest.ds->height; y++) {
7355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (vnc_and_bits(vs->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
7365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                int x;
7375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                uint8_t *guest_ptr;
7385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                uint8_t *server_ptr;
7395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                guest_ptr  = guest_row;
7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                server_ptr = server_row;
7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                for (x = 0; x < vs->guest.ds->width;
7445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                     x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
7455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    if (!vnc_get_bit(vs->guest.dirty[y], (x / 16)))
7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        continue;
7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    vnc_clear_bit(vs->guest.dirty[y], (x / 16));
7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        continue;
7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    memcpy(server_ptr, guest_ptr, cmp_bytes);
7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    vnc_set_bit(vs->server.dirty[y], (x / 16));
7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    has_dirty++;
7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            guest_row  += ds_get_linesize(vs->ds);
7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            server_row += ds_get_linesize(vs->ds);
7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!has_dirty && !vs->audio_cap && !vs->force_update) {
7605973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner            qemu_mod_timer(vs->timer, qemu_get_clock_ms(rt_clock) + VNC_REFRESH_INTERVAL);
7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return;
7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /*
7655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * Send screen updates to the vnc client using the server
7665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * surface and server dirty map.  guest surface updates
7675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * happening in parallel don't disturb us, the next pass will
7685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * send them to the client.
7695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         */
7705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        n_rectangles = 0;
7715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, 0);  /* msg id */
7725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, 0);
7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        saved_offset = vs->output.offset;
7745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u16(vs, 0);
7755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (y = 0; y < vs->server.ds->height; y++) {
7775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int x;
7785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int last_x = -1;
7795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            for (x = 0; x < vs->server.ds->width / 16; x++) {
7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (vnc_get_bit(vs->server.dirty[y], x)) {
7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    if (last_x == -1) {
7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        last_x = x;
7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    }
7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    vnc_clear_bit(vs->server.dirty[y], x);
7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                } else {
7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    if (last_x != -1) {
7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        n_rectangles++;
7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    }
7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    last_x = -1;
7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (last_x != -1) {
7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                n_rectangles++;
7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_flush(vs);
8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->force_update = 0;
8048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->csock != -1) {
8085973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        qemu_mod_timer(vs->timer, qemu_get_clock_ms(rt_clock) + VNC_REFRESH_INTERVAL);
8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_disconnect_finish(vs);
8118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* audio */
8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void audio_capture_notify(void *opaque, audcnotification_e cmd)
8178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    VncState *vs = opaque;
8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch (cmd) {
8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case AUD_CNOTIFY_DISABLE:
8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, 255);
8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, 1);
8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u16(vs, 0);
8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_flush(vs);
8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case AUD_CNOTIFY_ENABLE:
8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, 255);
8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, 1);
8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u16(vs, 1);
8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_flush(vs);
8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void audio_capture_destroy(void *opaque)
8388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void audio_capture(void *opaque, void *buf, int size)
8428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncState *vs = opaque;
8445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u8(vs, 255);
8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u8(vs, 1);
8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u16(vs, 2);
8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u32(vs, size);
8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write(vs, buf, size);
8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_flush(vs);
8518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void audio_add(VncState *vs)
8548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    Monitor *mon = cur_mon;
8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct audio_capture_ops ops;
8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->audio_cap) {
8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "audio already running\n");
8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ops.notify = audio_capture_notify;
8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ops.destroy = audio_capture_destroy;
8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ops.capture = audio_capture;
8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!vs->audio_cap) {
8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "Failed to add audio capture\n");
8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void audio_del(VncState *vs)
8748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->audio_cap) {
8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        AUD_del_capture(vs->audio_cap, vs);
8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->audio_cap = NULL;
8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_disconnect_start(VncState *vs)
8828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->csock == -1)
8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    closesocket(vs->csock);
8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->csock = -1;
8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_disconnect_finish(VncState *vs)
8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_del_timer(vs->timer);
8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free_timer(vs->timer);
8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->input.buffer) qemu_free(vs->input.buffer);
8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->output.buffer) qemu_free(vs->output.buffer);
8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_TLS
8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_tls_client_cleanup(vs);
8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_TLS */
8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_sasl_client_cleanup(vs);
9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_SASL */
9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    audio_del(vs);
9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncState *p, *parent = NULL;
9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (p = vs->vd->clients; p != NULL; p = p->next) {
9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (p == vs) {
9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (parent)
9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                parent->next = p->next;
9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            else
9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->vd->clients = p->next;
9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        parent = p;
9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!vs->vd->clients)
9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dcl->idle = 1;
9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(vs->server.ds->data);
9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(vs->server.ds);
9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(vs->guest.ds);
9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(vs);
9228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
9238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint vnc_client_io_error(VncState *vs, int ret, int last_errno)
9258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
9268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret == 0 || ret == -1) {
9278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ret == -1) {
9288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            switch (last_errno) {
9298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                case EINTR:
9308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                case EAGAIN:
9318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef _WIN32
9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                case WSAEWOULDBLOCK:
9338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
9348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    return 0;
9358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                default:
9368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    break;
9378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
9388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
9398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                  ret, ret < 0 ? last_errno : 0);
9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_disconnect_start(vs);
9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
9458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
9468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ret;
9478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
9488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_client_error(VncState *vs)
9518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VNC_DEBUG("Closing down client sock: protocol error\n");
9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_disconnect_start(vs);
9548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
9558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Called to write a chunk of data to the client socket. The data may
9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * be the raw data, or may have already been encoded by SASL.
9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The data will be written either straight onto the socket, or
9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * NB, it is theoretically possible to have 2 layers of encryption,
9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * both SASL, and this TLS layer. It is highly unlikely in practice
9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * though, since SASL encryption will typically be a no-op if TLS
9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * is active
9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
9685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Returns the number of bytes written, which may be less than
9695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the requested 'datalen' if the socket would block. Returns
9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * -1 on error, and disconnects the client socket.
9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
9725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerlong vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
9738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
9748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    long ret;
9758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
9765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->tls.session) {
9775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = gnutls_write(vs->tls.session, data, datalen);
9785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret < 0) {
9795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (ret == GNUTLS_E_AGAIN)
9805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                errno = EAGAIN;
9815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            else
9825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                errno = EIO;
9835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
9845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
9858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else
9868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif /* CONFIG_VNC_TLS */
9875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = send(vs->csock, (const void *)data, datalen, 0);
9885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
9895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return vnc_client_io_error(vs, ret, socket_error());
9905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
9945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Called to write buffered data to the client socket, when not
9955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * using any SASL SSF encryption layers. Will write as much data
9965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * as possible without blocking. If all buffered data is written,
9975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * will switch the FD poll() handler back to read monitoring.
9985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
9995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Returns the number of bytes written, which may be less than
10005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the buffered output data if the socket would block. Returns
10015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * -1 on error, and disconnects the client socket.
10025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic long vnc_client_write_plain(VncState *vs)
10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    long ret;
10065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
10095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner              vs->output.buffer, vs->output.capacity, vs->output.offset,
10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner              vs->sasl.waitWriteSSF);
10115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->sasl.conn &&
10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->sasl.runSSF &&
10145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->sasl.waitWriteSSF) {
10155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret)
10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->sasl.waitWriteSSF -= ret;
10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_SASL */
10205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
10218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!ret)
10225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
10238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
10258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->output.offset -= ret;
10268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->output.offset == 0) {
10285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
10298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
10325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
10365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * First function called whenever there is data to be written to
10375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the client socket. Will delegate actual work according to whether
10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * SASL SSF layers are enabled (thus requiring encryption calls)
10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
10405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_client_write(void *opaque)
10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    long ret;
10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncState *vs = opaque;
10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->sasl.conn &&
10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->sasl.runSSF &&
10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        !vs->sasl.waitWriteSSF)
10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = vnc_client_write_sasl(vs);
10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_SASL */
10525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = vnc_client_write_plain(vs);
10538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
10548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
10568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
10578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->read_handler = func;
10588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->read_handler_expect = expecting;
10598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
10608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Called to read a chunk of data from the client socket. The data may
10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * be the raw data, or may need to be further decoded by SASL.
10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The data will be read either straight from to the socket, or
10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * NB, it is theoretically possible to have 2 layers of encryption,
10695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * both SASL, and this TLS layer. It is highly unlikely in practice
10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * though, since SASL encryption will typically be a no-op if TLS
10715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * is active
10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Returns the number of bytes read, which may be less than
10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the requested 'datalen' if the socket would block. Returns
10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * -1 on error, and disconnects the client socket.
10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerlong vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
10788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
10798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    long ret;
10808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
10815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->tls.session) {
10825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = gnutls_read(vs->tls.session, data, datalen);
10835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret < 0) {
10845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (ret == GNUTLS_E_AGAIN)
10855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                errno = EAGAIN;
10865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            else
10875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                errno = EIO;
10885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
10908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else
10918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif /* CONFIG_VNC_TLS */
10925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = recv(vs->csock, (void *)data, datalen, 0);
10935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
10945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return vnc_client_io_error(vs, ret, socket_error());
10955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
10995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Called to read data from the client socket to the input buffer,
11005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * when not using any SASL SSF encryption layers. Will read as much
11015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * data as possible without blocking.
11025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
11035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Returns the number of bytes read. Returns -1 on error, and
11045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * disconnects the client socket.
11055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
11065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic long vnc_client_read_plain(VncState *vs)
11075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret;
11095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
11105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner              vs->input.buffer, vs->input.capacity, vs->input.offset);
11115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    buffer_reserve(&vs->input, 4096);
11125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
11135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!ret)
11145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
11158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->input.offset += ret;
11165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
11175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
11185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
11215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * First function called whenever there is more data to be read from
11225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the client socket. Will delegate actual work according to whether
11235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * SASL SSF layers are enabled (thus requiring decryption calls)
11245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
11255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_client_read(void *opaque)
11265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncState *vs = opaque;
11285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    long ret;
11295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
11315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->sasl.conn && vs->sasl.runSSF)
11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = vnc_client_read_sasl(vs);
11335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
11345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_SASL */
11355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = vnc_client_read_plain(vs);
11365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!ret) {
11375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->csock == -1)
11385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_disconnect_finish(vs);
11395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
11405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
11435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        size_t len = vs->read_handler_expect;
11445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int ret;
11455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = vs->read_handler(vs, vs->input.buffer, len);
11475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->csock == -1) {
11485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_disconnect_finish(vs);
11495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return;
11505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
11515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!ret) {
11535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
11545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->input.offset -= len;
11555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->read_handler_expect = ret;
11575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
11588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_write(VncState *vs, const void *data, size_t len)
11628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buffer_reserve(&vs->output, len);
11648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->csock != -1 && buffer_empty(&vs->output)) {
11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
11678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buffer_append(&vs->output, data, len);
11708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_write_s32(VncState *vs, int32_t value)
11738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u32(vs, *(uint32_t *)&value);
11758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_write_u32(VncState *vs, uint32_t value)
11788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t buf[4];
11808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buf[0] = (value >> 24) & 0xFF;
11828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buf[1] = (value >> 16) & 0xFF;
11838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buf[2] = (value >>  8) & 0xFF;
11848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buf[3] = value & 0xFF;
11858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write(vs, buf, 4);
11878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_write_u16(VncState *vs, uint16_t value)
11908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t buf[2];
11928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buf[0] = (value >> 8) & 0xFF;
11948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buf[1] = value & 0xFF;
11958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write(vs, buf, 2);
11978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_write_u8(VncState *vs, uint8_t value)
12008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write(vs, (char *)&value, 1);
12028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid vnc_flush(VncState *vs)
12058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->csock != -1 && vs->output.offset)
12075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_client_write(vs);
12088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint8_t read_u8(uint8_t *data, size_t offset)
12118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return data[offset];
12138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint16_t read_u16(uint8_t *data, size_t offset)
12168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
12188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint32_t read_s32(uint8_t *data, size_t offset)
12218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
12235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                     (data[offset + 2] << 8) | data[offset + 3]);
12248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneruint32_t read_u32(uint8_t *data, size_t offset)
12278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ((data[offset] << 24) | (data[offset + 1] << 16) |
12295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            (data[offset + 2] << 8) | data[offset + 3]);
12308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void client_cut_text(VncState *vs, size_t len, uint8_t *text)
12335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
12348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void check_pointer_type_change(VncState *vs, int absolute)
12378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
12395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, 0);
12405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, 0);
12415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u16(vs, 1);
12425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_framebuffer_update(vs, absolute, 0,
12435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               ds_get_width(vs->ds), ds_get_height(vs->ds),
12445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               VNC_ENCODING_POINTER_TYPE_CHANGE);
12455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_flush(vs);
12468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->absolute = absolute;
12488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pointer_event(VncState *vs, int button_mask, int x, int y)
12518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int buttons = 0;
12538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int dz = 0;
12548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (button_mask & 0x01)
12565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        buttons |= MOUSE_EVENT_LBUTTON;
12578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (button_mask & 0x02)
12585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        buttons |= MOUSE_EVENT_MBUTTON;
12598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (button_mask & 0x04)
12605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        buttons |= MOUSE_EVENT_RBUTTON;
12618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (button_mask & 0x08)
12625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dz = -1;
12638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (button_mask & 0x10)
12645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dz = 1;
12658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->absolute) {
12675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
12685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        y * 0x7FFF / (ds_get_height(vs->ds) - 1),
12695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        dz, buttons);
12705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
12715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        x -= 0x7FFF;
12725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        y -= 0x7FFF;
12735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        kbd_mouse_event(x, y, dz, buttons);
12758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
12765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->last_x != -1)
12775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            kbd_mouse_event(x - vs->last_x,
12785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            y - vs->last_y,
12795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            dz, buttons);
12805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->last_x = x;
12815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->last_y = y;
12828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    check_pointer_type_change(vs, kbd_mouse_is_absolute());
12858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void reset_keys(VncState *vs)
12888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
12908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i = 0; i < 256; i++) {
12918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (vs->modifiers_state[i]) {
12928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (i & 0x80)
12938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keycode(0xe0);
12948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            kbd_put_keycode(i | 0x80);
12958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vs->modifiers_state[i] = 0;
12968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
12978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void press_key(VncState *vs, int keysym)
13018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
13025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f);
13035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80);
13048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
13058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void do_key_event(VncState *vs, int down, int keycode, int sym)
13078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
13088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* QEMU console switch */
13098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch(keycode) {
13108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x2a:                          /* Left Shift */
13118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x36:                          /* Right Shift */
13128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x1d:                          /* Left CTRL */
13138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x9d:                          /* Right CTRL */
13148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x38:                          /* Left ALT */
13158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0xb8:                          /* Right ALT */
13168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (down)
13178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vs->modifiers_state[keycode] = 1;
13188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
13198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vs->modifiers_state[keycode] = 0;
13208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
13218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x02 ... 0x0a: /* '1' to '9' keys */
13228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
13238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* Reset the modifiers sent to the current console */
13248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            reset_keys(vs);
13258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            console_select(keycode - 0x02);
13268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return;
13278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
13288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
13295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 0x3a:                        /* CapsLock */
13305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 0x45:                        /* NumLock */
13318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!down)
13328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vs->modifiers_state[keycode] ^= 1;
13338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
13348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
13358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
13378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* If the numlock state needs to change then simulate an additional
13388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           keypress before sending this one.  This will happen if the user
13398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           toggles numlock away from the VNC window.
13408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        */
13415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
13428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (!vs->modifiers_state[0x45]) {
13438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                vs->modifiers_state[0x45] = 1;
13448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                press_key(vs, 0xff7f);
13458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
13468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
13478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (vs->modifiers_state[0x45]) {
13488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                vs->modifiers_state[0x45] = 0;
13498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                press_key(vs, 0xff7f);
13508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
13518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
13528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
13538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (is_graphic_console()) {
13558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (keycode & 0x80)
13568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            kbd_put_keycode(0xe0);
13578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (down)
13588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            kbd_put_keycode(keycode & 0x7f);
13598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
13608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            kbd_put_keycode(keycode | 0x80);
13618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
13628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* QEMU console emulation */
13638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (down) {
13645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int numlock = vs->modifiers_state[0x45];
13658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            switch (keycode) {
13668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x2a:                          /* Left Shift */
13678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x36:                          /* Right Shift */
13688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x1d:                          /* Left CTRL */
13698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x9d:                          /* Right CTRL */
13708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0x38:                          /* Left ALT */
13718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xb8:                          /* Right ALT */
13728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
13738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xc8:
13748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(QEMU_KEY_UP);
13758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
13768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xd0:
13778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(QEMU_KEY_DOWN);
13788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
13798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xcb:
13808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(QEMU_KEY_LEFT);
13818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
13828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xcd:
13838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(QEMU_KEY_RIGHT);
13848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
13858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xd3:
13868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(QEMU_KEY_DELETE);
13878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
13888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xc7:
13898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(QEMU_KEY_HOME);
13908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
13918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xcf:
13928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(QEMU_KEY_END);
13938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
13948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xc9:
13958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(QEMU_KEY_PAGEUP);
13968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
13978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case 0xd1:
13988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(QEMU_KEY_PAGEDOWN);
13998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
14005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x47:
14025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x48:
14055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
14065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x49:
14085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
14095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x4b:
14115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
14125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x4c:
14145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym('5');
14155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x4d:
14175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
14185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x4f:
14205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
14215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x50:
14235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
14245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x51:
14265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
14275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x52:
14295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym('0');
14305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x53:
14325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
14335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0xb5:
14365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym('/');
14375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x37:
14395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym('*');
14405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x4a:
14425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym('-');
14435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x4e:
14455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym('+');
14465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0x9c:
14485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                kbd_put_keysym('\n');
14495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
14505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            default:
14528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                kbd_put_keysym(sym);
14538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
14548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
14558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
14568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
14578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
14588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void key_event(VncState *vs, int down, uint32_t sym)
14608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
14618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int keycode;
14628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
14645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sym = sym - 'A' + 'a';
14658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF);
14678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    do_key_event(vs, down, keycode, sym);
14688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
14698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ext_key_event(VncState *vs, int down,
14718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                          uint32_t sym, uint16_t keycode)
14728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
14738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* if the user specifies a keyboard layout, always use it */
14748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (keyboard_layout)
14758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        key_event(vs, down, sym);
14768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
14778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        do_key_event(vs, down, keycode, sym);
14788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
14798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void framebuffer_update_request(VncState *vs, int incremental,
14815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       int x_position, int y_position,
14825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       int w, int h)
14835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (x_position > ds_get_width(vs->ds))
14855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        x_position = ds_get_width(vs->ds);
14865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (y_position > ds_get_height(vs->ds))
14875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        y_position = ds_get_height(vs->ds);
14885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (x_position + w >= ds_get_width(vs->ds))
14895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        w = ds_get_width(vs->ds)  - x_position;
14905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (y_position + h >= ds_get_height(vs->ds))
14915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        h = ds_get_height(vs->ds) - y_position;
14928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
14948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->need_update = 1;
14958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!incremental) {
14965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->force_update = 1;
14975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (i = 0; i < h; i++) {
14985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_set_bits(vs->guest.dirty[y_position + i],
14995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
15005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_set_bits(vs->server.dirty[y_position + i],
15015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
15025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
15038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
15048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
15058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void send_ext_key_event_ack(VncState *vs)
15078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
15088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u8(vs, 0);
15098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u8(vs, 0);
15108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u16(vs, 1);
15115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
15125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           VNC_ENCODING_EXT_KEY_EVENT);
15135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_flush(vs);
15145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
15155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void send_ext_audio_ack(VncState *vs)
15175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
15185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u8(vs, 0);
15195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u8(vs, 0);
15205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u16(vs, 1);
15215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
15225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           VNC_ENCODING_AUDIO);
15238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_flush(vs);
15248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
15258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
15278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
15288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
15295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned int enc = 0;
15308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_zlib_init(vs);
15325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->features = 0;
15335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->vnc_encoding = 0;
15345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->tight_compression = 9;
15355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->tight_quality = 9;
15368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->absolute = -1;
15378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = n_encodings - 1; i >= 0; i--) {
15395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        enc = encodings[i];
15405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch (enc) {
15415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_RAW:
15425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->vnc_encoding = enc;
15435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_COPYRECT:
15455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->features |= VNC_FEATURE_COPYRECT_MASK;
15465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_HEXTILE:
15485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->features |= VNC_FEATURE_HEXTILE_MASK;
15495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->vnc_encoding = enc;
15505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_ZLIB:
15525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->features |= VNC_FEATURE_ZLIB_MASK;
15535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->vnc_encoding = enc;
15545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_DESKTOPRESIZE:
15565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->features |= VNC_FEATURE_RESIZE_MASK;
15575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_POINTER_TYPE_CHANGE:
15595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
15605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_EXT_KEY_EVENT:
15628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            send_ext_key_event_ack(vs);
15638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
15645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_AUDIO:
15655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            send_ext_audio_ack(vs);
15665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_WMVi:
15685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->features |= VNC_FEATURE_WMVI_MASK;
15695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
15715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->tight_compression = (enc & 0x0F);
15725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
15745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->tight_quality = (enc & 0x0F);
15755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        default:
15775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
15788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
15795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
15808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
15818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    check_pointer_type_change(vs, kbd_mouse_is_absolute());
15838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
15848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void set_pixel_conversion(VncState *vs)
15868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
15875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
15885973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) &&
15895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
15908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vs->write_pixels = vnc_write_pixels_copy;
15915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch (vs->ds->surface->pf.bits_per_pixel) {
15925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 8:
15935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->send_hextile_tile = send_hextile_tile_8;
15945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
15955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 16:
15965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->send_hextile_tile = send_hextile_tile_16;
15975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
15985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 32:
15995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->send_hextile_tile = send_hextile_tile_32;
16005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
16018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
16025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
16038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vs->write_pixels = vnc_write_pixels_generic;
16045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch (vs->ds->surface->pf.bits_per_pixel) {
16055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 8:
16065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->send_hextile_tile = send_hextile_tile_generic_8;
16075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
16085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 16:
16095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->send_hextile_tile = send_hextile_tile_generic_16;
16105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
16115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 32:
16125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->send_hextile_tile = send_hextile_tile_generic_32;
16135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
16145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
16155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
16175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void set_pixel_format(VncState *vs,
16195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             int bits_per_pixel, int depth,
16205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             int big_endian_flag, int true_color_flag,
16215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             int red_max, int green_max, int blue_max,
16225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             int red_shift, int green_shift, int blue_shift)
16235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
16245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!true_color_flag) {
16255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_client_error(vs);
16265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
16278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
16288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds = *(vs->guest.ds);
16305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.rmax = red_max;
16315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    count_bits(vs->clientds.pf.rbits, red_max);
16325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.rshift = red_shift;
16335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.rmask = red_max << red_shift;
16345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.gmax = green_max;
16355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    count_bits(vs->clientds.pf.gbits, green_max);
16365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.gshift = green_shift;
16375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.gmask = green_max << green_shift;
16385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.bmax = blue_max;
16395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    count_bits(vs->clientds.pf.bbits, blue_max);
16405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.bshift = blue_shift;
16415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.bmask = blue_max << blue_shift;
16425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.bits_per_pixel = bits_per_pixel;
16435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
16445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
16455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
16465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    set_pixel_conversion(vs);
16488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vga_hw_invalidate();
16508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vga_hw_update();
16518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
16528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void pixel_format_message (VncState *vs) {
16548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char pad[3] = { 0, 0, 0 };
16558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
16575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
16588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
165920894ae3fa98f82da925fbeb72e616eef509758aDavid 'Digit' Turner#ifdef HOST_WORDS_BIGENDIAN
16608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u8(vs, 1);             /* big-endian-flag */
16618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
16628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u8(vs, 0);             /* big-endian-flag */
16638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
16648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u8(vs, 1);             /* true-color-flag */
16655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u16(vs, vs->ds->surface->pf.rmax);     /* red-max */
16665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u16(vs, vs->ds->surface->pf.gmax);     /* green-max */
16675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u16(vs, vs->ds->surface->pf.bmax);     /* blue-max */
16685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u8(vs, vs->ds->surface->pf.rshift);    /* red-shift */
16695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u8(vs, vs->ds->surface->pf.gshift);    /* green-shift */
16705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u8(vs, vs->ds->surface->pf.bshift);    /* blue-shift */
16715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vs->ds->surface->pf.bits_per_pixel == 32)
16728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vs->send_hextile_tile = send_hextile_tile_32;
16735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else if (vs->ds->surface->pf.bits_per_pixel == 16)
16748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vs->send_hextile_tile = send_hextile_tile_16;
16755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else if (vs->ds->surface->pf.bits_per_pixel == 8)
16768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vs->send_hextile_tile = send_hextile_tile_8;
16775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds = *(vs->ds->surface);
16785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
16798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->write_pixels = vnc_write_pixels_copy;
16808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write(vs, pad, 3);           /* padding */
16828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
16838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_dpy_setdata(DisplayState *ds)
16858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
16865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* We don't have to do anything */
16875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
16888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_colordepth(VncState *vs)
16905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
16915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
16928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Sending a WMVi message to notify the client*/
16938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vnc_write_u8(vs, 0);  /* msg id */
16948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vnc_write_u8(vs, 0);
16958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vnc_write_u16(vs, 1); /* number of rects */
16965973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds),
16975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               ds_get_height(vs->ds), VNC_ENCODING_WMVi);
16988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pixel_format_message(vs);
16998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vnc_flush(vs);
17008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
17015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        set_pixel_conversion(vs);
17028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
17038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
17048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
17068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
17078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
17088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t limit;
17098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (data[0]) {
17118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0:
17125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len == 1)
17135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 20;
17148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
17165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         read_u8(data, 6), read_u8(data, 7),
17175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         read_u16(data, 8), read_u16(data, 10),
17185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         read_u16(data, 12), read_u8(data, 14),
17195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         read_u8(data, 15), read_u8(data, 16));
17205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
17215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 2:
17225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len == 1)
17235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 4;
17245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len == 4) {
17265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            limit = read_u16(data, 2);
17275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (limit > 0)
17285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return 4 + (limit * 4);
17295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else
17305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            limit = read_u16(data, 2);
17315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (i = 0; i < limit; i++) {
17335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int32_t val = read_s32(data, 4 + (i * 4));
17345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(data + 4 + (i * 4), &val, sizeof(val));
17355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
17368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        set_encodings(vs, (int32_t *)(data + 4), limit);
17385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
17398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 3:
17405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len == 1)
17415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 10;
17428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        framebuffer_update_request(vs,
17445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
17455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   read_u16(data, 6), read_u16(data, 8));
17465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
17478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 4:
17485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len == 1)
17495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 8;
17508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        key_event(vs, read_u8(data, 1), read_u32(data, 4));
17525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
17538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 5:
17545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len == 1)
17555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 6;
17568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
17585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
17598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 6:
17605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len == 1)
17615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 8;
17628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len == 8) {
17648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint32_t dlen = read_u32(data, 4);
17658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (dlen > 0)
17668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                return 8 + dlen;
17678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
17688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        client_cut_text(vs, read_u32(data, 4), data + 8);
17705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
17718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 255:
17728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (len == 1)
17738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 2;
17748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        switch (read_u8(data, 1)) {
17768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 0:
17778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (len == 2)
17788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                return 12;
17798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ext_key_event(vs, read_u16(data, 2),
17818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                          read_u32(data, 4), read_u32(data, 8));
17828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
17835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 1:
17845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (len == 2)
17855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return 4;
17865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            switch (read_u16 (data, 2)) {
17885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 0:
17895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                audio_add(vs);
17905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
17915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 1:
17925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                audio_del(vs);
17935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
17945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case 2:
17955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (len == 4)
17965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    return 10;
17975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                switch (read_u8(data, 4)) {
17985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                case 0: vs->as.fmt = AUD_FMT_U8; break;
17995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                case 1: vs->as.fmt = AUD_FMT_S8; break;
18005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                case 2: vs->as.fmt = AUD_FMT_U16; break;
18015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                case 3: vs->as.fmt = AUD_FMT_S16; break;
18025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                case 4: vs->as.fmt = AUD_FMT_U32; break;
18035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                case 5: vs->as.fmt = AUD_FMT_S32; break;
18045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                default:
18055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    printf("Invalid audio format %d\n", read_u8(data, 4));
18065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    vnc_client_error(vs);
18075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    break;
18085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
18095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->as.nchannels = read_u8(data, 5);
18105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
18115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    printf("Invalid audio channel coount %d\n",
18125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           read_u8(data, 5));
18135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    vnc_client_error(vs);
18145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    break;
18155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
18165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->as.freq = read_u32(data, 6);
18175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
18185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            default:
18195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                printf ("Invalid audio message %d\n", read_u8(data, 4));
18205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vnc_client_error(vs);
18215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
18225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
18235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
18245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        default:
18268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            printf("Msg: %d\n", read_u16(data, 0));
18278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_client_error(vs);
18288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
18298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
18308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
18318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
18325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        printf("Msg: %d\n", data[0]);
18335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_client_error(vs);
18345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
18358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
18368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_read_when(vs, protocol_client_msg, 1);
18388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
18398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
18408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
18428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
18438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char buf[1024];
18448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int size;
18458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u16(vs, ds_get_width(vs->ds));
18475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_write_u16(vs, ds_get_height(vs->ds));
18488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pixel_format_message(vs);
18508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (qemu_name)
18528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
18538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
18548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        size = snprintf(buf, sizeof(buf), "QEMU");
18558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write_u32(vs, size);
18578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write(vs, buf, size);
18588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_flush(vs);
18598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_read_when(vs, protocol_client_msg, 1);
18618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
18638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
18648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid start_client_init(VncState *vs)
18665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_read_when(vs, protocol_client_init, 1);
18685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void make_challenge(VncState *vs)
18718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
18728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
18738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    srand(time(NULL)+getpid()+getpid()*987654+rand());
18758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0 ; i < sizeof(vs->challenge) ; i++)
18778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
18788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
18798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
18818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
18828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
18838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i, j, pwlen;
18848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned char key[8];
18858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!vs->vd->password || !vs->vd->password[0]) {
18875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("No password configured on server");
18885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u32(vs, 1); /* Reject auth */
18895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->minor >= 8) {
18905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            static const char err[] = "Authentication failed";
18915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_write_u32(vs, sizeof(err));
18925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_write(vs, err, sizeof(err));
18935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
18945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_flush(vs);
18955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_client_error(vs);
18965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
18978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
18988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
18998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
19008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Calculate the expected challenge response */
19025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pwlen = strlen(vs->vd->password);
19038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i=0; i<sizeof(key); i++)
19045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        key[i] = i<pwlen ? vs->vd->password[i] : 0;
19058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    deskey(key, EN0);
19068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
19078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        des(response+j, response+j);
19088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Compare expected vs actual challenge response */
19108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
19115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("Client challenge reponse did not match\n");
19125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u32(vs, 1); /* Reject auth */
19135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->minor >= 8) {
19145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            static const char err[] = "Authentication failed";
19155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_write_u32(vs, sizeof(err));
19165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_write(vs, err, sizeof(err));
19175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
19185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_flush(vs);
19195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_client_error(vs);
19208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
19215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("Accepting VNC challenge response\n");
19225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u32(vs, 0); /* Accept auth */
19235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_flush(vs);
19248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        start_client_init(vs);
19268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
19278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
19288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
19298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid start_auth_vnc(VncState *vs)
19318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
19328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    make_challenge(vs);
19338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Send client a 'random' challenge */
19348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write(vs, vs->challenge, sizeof(vs->challenge));
19358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_flush(vs);
19368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
19388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
19398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
19428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
19438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* We only advertise 1 auth scheme at a time, so client
19448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * must pick the one we sent. Verify this */
19455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (data[0] != vs->vd->auth) { /* Reject auth */
19465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
19478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       vnc_write_u32(vs, 1);
19488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       if (vs->minor >= 8) {
19498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           static const char err[] = "Authentication failed";
19508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           vnc_write_u32(vs, sizeof(err));
19518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           vnc_write(vs, err, sizeof(err));
19528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       }
19538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       vnc_client_error(vs);
19548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else { /* Accept requested auth */
19558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
19565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       switch (vs->vd->auth) {
19578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       case VNC_AUTH_NONE:
19588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           VNC_DEBUG("Accept auth none\n");
19598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           if (vs->minor >= 8) {
19608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               vnc_write_u32(vs, 0); /* Accept auth completion */
19618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               vnc_flush(vs);
19628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           }
19635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           start_client_init(vs);
19648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           break;
19658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       case VNC_AUTH_VNC:
19678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           VNC_DEBUG("Start VNC auth\n");
19685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           start_auth_vnc(vs);
19695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           break;
19708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
19728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       case VNC_AUTH_VENCRYPT:
19738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           VNC_DEBUG("Accept VeNCrypt auth\n");;
19745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           start_auth_vencrypt(vs);
19755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           break;
19768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif /* CONFIG_VNC_TLS */
19778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
19795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       case VNC_AUTH_SASL:
19805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           VNC_DEBUG("Accept SASL auth\n");
19815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           start_auth_sasl(vs);
19825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           break;
19835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_SASL */
19845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       default: /* Should not be possible, but just in case */
19865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
19878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           vnc_write_u8(vs, 1);
19888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           if (vs->minor >= 8) {
19898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               static const char err[] = "Authentication failed";
19908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               vnc_write_u32(vs, sizeof(err));
19918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               vnc_write(vs, err, sizeof(err));
19928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           }
19938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           vnc_client_error(vs);
19948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       }
19958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
19968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
19978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
19988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
19998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int protocol_version(VncState *vs, uint8_t *version, size_t len)
20008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
20018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char local[13];
20028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(local, version, 12);
20048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    local[12] = 0;
20058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
20075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("Malformed protocol version %s\n", local);
20085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_client_error(vs);
20095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
20108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
20118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
20128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->major != 3 ||
20135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (vs->minor != 3 &&
20145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         vs->minor != 4 &&
20155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         vs->minor != 5 &&
20165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         vs->minor != 7 &&
20175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         vs->minor != 8)) {
20185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("Unsupported client version\n");
20195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u32(vs, VNC_AUTH_INVALID);
20205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_flush(vs);
20215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_client_error(vs);
20225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
20238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
20248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
20258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * as equivalent to v3.3 by servers
20268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
20278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->minor == 4 || vs->minor == 5)
20285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->minor = 3;
20298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->minor == 3) {
20315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vs->vd->auth == VNC_AUTH_NONE) {
20328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            VNC_DEBUG("Tell client auth none\n");
20335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_write_u32(vs, vs->vd->auth);
20348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_flush(vs);
20355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            start_client_init(vs);
20365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       } else if (vs->vd->auth == VNC_AUTH_VNC) {
20378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            VNC_DEBUG("Tell client VNC auth\n");
20385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_write_u32(vs, vs->vd->auth);
20398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_flush(vs);
20408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            start_auth_vnc(vs);
20418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       } else {
20425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
20438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_write_u32(vs, VNC_AUTH_INVALID);
20448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_flush(vs);
20458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            vnc_client_error(vs);
20468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       }
20478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
20485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
20495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, 1); /* num auth */
20505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_write_u8(vs, vs->vd->auth);
20515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_read_when(vs, protocol_client_auth, 1);
20525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_flush(vs);
20538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
20548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
20568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
20578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vnc_connect(VncDisplay *vd, int csock)
20598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
20605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncState *vs = qemu_mallocz(sizeof(VncState));
20615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->csock = csock;
20625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VNC_DEBUG("New client on socket %d\n", csock);
20645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dcl->idle = 0;
20658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    socket_set_nonblock(vs->csock);
20668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
20675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->vd = vd;
20695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->ds = vd->ds;
20705973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    vs->timer = qemu_new_timer_ms(rt_clock, vnc_update_client, vs);
20715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->last_x = -1;
20725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->last_y = -1;
20735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->as.freq = 44100;
20755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->as.nchannels = 2;
20765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->as.fmt = AUD_FMT_S16;
20775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->as.endianness = 0;
20785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_resize(vs);
20808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_write(vs, "RFB 003.008\n", 12);
20818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_flush(vs);
20828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_read_when(vs, protocol_version, 12);
20835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    reset_keys(vs);
20845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->next = vd->clients;
20865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vd->clients = vs;
20875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_update_client(vs);
20895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* vs might be free()ed here */
20908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
20918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void vnc_listen_read(void *opaque)
20938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
20945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncDisplay *vs = opaque;
20955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_in addr;
20965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socklen_t addrlen = sizeof(addr);
20978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
20988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Catch-up */
20998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vga_hw_update();
21008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
21025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (csock != -1) {
21035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vnc_connect(vs, csock);
21048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
21058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
21068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid vnc_display_init(DisplayState *ds)
21088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
21095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncDisplay *vs = qemu_mallocz(sizeof(*vs));
21108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
21128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ds->opaque = vs;
21145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dcl->idle = 1;
21155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vnc_display = vs;
21168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->lsock = -1;
21188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->ds = ds;
21208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (keyboard_layout)
21225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
21238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else
21245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
21258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!vs->kbd_layout)
21275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        exit(1);
21288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dcl->dpy_copy = vnc_dpy_copy;
21305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dcl->dpy_update = vnc_dpy_update;
21315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dcl->dpy_resize = vnc_dpy_resize;
21325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dcl->dpy_setdata = vnc_dpy_setdata;
21335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    register_displaychangelistener(ds, dcl);
21348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
21358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid vnc_display_close(DisplayState *ds)
21388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
21395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
21408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!vs)
21425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
21438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->display) {
21445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(vs->display);
21455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->display = NULL;
21468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
21478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->lsock != -1) {
21485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
21495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        close(vs->lsock);
21505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->lsock = -1;
21518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
21528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->auth = VNC_AUTH_INVALID;
21538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
21548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vs->subauth = VNC_AUTH_INVALID;
21555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vs->tls.x509verify = 0;
21568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
21578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
21588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint vnc_display_password(DisplayState *ds, const char *password)
21608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
21615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
21628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (vs->password) {
21645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(vs->password);
21655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->password = NULL;
21668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
21678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (password && password[0]) {
21685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!(vs->password = qemu_strdup(password)))
21695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -1;
21708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
21718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
21738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
21748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerchar *vnc_display_local_addr(DisplayState *ds)
21765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
21775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
21785973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner
21795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return vnc_socket_local_addr("%s:%s", vs->lsock);
21805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
21815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint vnc_display_open(DisplayState *ds, const char *display)
21838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
21845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
21858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char *options;
21868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int password = 0;
21878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int reverse = 0;
21885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int to_port = 0;
21898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
21908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int tls = 0, x509 = 0;
21918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
21925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
21935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int sasl = 0;
21945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int saslErr;
21955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
21965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int acl = 0;
21978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
21985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!vnc_display)
21995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
22008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    vnc_display_close(ds);
22018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (strcmp(display, "none") == 0)
22025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
22038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!(vs->display = strdup(display)))
22055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
22068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    options = display;
22088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while ((options = strchr(options, ','))) {
22095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        options++;
22105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (strncmp(options, "password", 8) == 0) {
22115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            password = 1; /* Require password auth */
22125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (strncmp(options, "reverse", 7) == 0) {
22135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            reverse = 1;
22145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (strncmp(options, "to=", 3) == 0) {
22155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            to_port = atoi(options+3) + 5900;
22165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
22175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (strncmp(options, "sasl", 4) == 0) {
22185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            sasl = 1; /* Require SASL auth */
22195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
22208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
22215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (strncmp(options, "tls", 3) == 0) {
22225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            tls = 1; /* Require TLS */
22235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (strncmp(options, "x509", 4) == 0) {
22245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            char *start, *end;
22255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            x509 = 1; /* Require x509 certificates */
22265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (strncmp(options, "x509verify", 10) == 0)
22275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->tls.x509verify = 1; /* ...and verify client certs */
22285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* Now check for 'x509=/some/path' postfix
22305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             * and use that to setup x509 certificate/key paths */
22315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            start = strchr(options, '=');
22325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            end = strchr(options, ',');
22335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (start && (!end || (start < end))) {
22345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                int len = end ? end-(start+1) : strlen(start+1);
22355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                char *path = qemu_strndup(start + 1, len);
22365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                VNC_DEBUG("Trying certificate path '%s'\n", path);
22385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
22395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
22405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    qemu_free(path);
22415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    qemu_free(vs->display);
22425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    vs->display = NULL;
22435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    return -1;
22445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
22458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                qemu_free(path);
22465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
22475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr, "No certificate path provided\n");
22485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                qemu_free(vs->display);
22495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->display = NULL;
22505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return -1;
22515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
22528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
22535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (strncmp(options, "acl", 3) == 0) {
22545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            acl = 1;
22555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
22578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
22588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
22595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (acl && x509 && vs->tls.x509verify) {
22605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
22615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr, "Failed to create x509 dname ACL\n");
22625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            exit(1);
22635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
22658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
22665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
22675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (acl && sasl) {
22685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
22695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr, "Failed to create username ACL\n");
22705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            exit(1);
22715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
22738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
22745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /*
22765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Combinations we support here:
22775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *
22785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *  - no-auth                (clear text, no auth)
22795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *  - password               (clear text, weak auth)
22805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *  - sasl                   (encrypt, good auth *IF* using Kerberos via GSSAPI)
22815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *  - tls                    (encrypt, weak anonymous creds, no auth)
22825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *  - tls + password         (encrypt, weak anonymous creds, weak auth)
22835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *  - tls + sasl             (encrypt, weak anonymous creds, good auth)
22845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *  - tls + x509             (encrypt, good x509 creds, no auth)
22855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *  - tls + x509 + password  (encrypt, good x509 creds, weak auth)
22865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *  - tls + x509 + sasl      (encrypt, good x509 creds, good auth)
22875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *
22885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * NB1. TLS is a stackable auth scheme.
22895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * NB2. the x509 schemes have option to validate a client cert dname
22905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
22915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (password) {
22925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_TLS
22935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (tls) {
22945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->auth = VNC_AUTH_VENCRYPT;
22955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (x509) {
22965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
22975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
22985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
22995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
23005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
23015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
23025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
23035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_TLS */
23045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            VNC_DEBUG("Initializing VNC server with password auth\n");
23055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->auth = VNC_AUTH_VNC;
23065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_TLS
23075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->subauth = VNC_AUTH_INVALID;
23085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
23095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_TLS */
23105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
23115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (sasl) {
23125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_TLS
23135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (tls) {
23145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->auth = VNC_AUTH_VENCRYPT;
23155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (x509) {
23165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
23175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
23185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
23195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
23205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
23215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
23225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
23235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_TLS */
23245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            VNC_DEBUG("Initializing VNC server with SASL auth\n");
23255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->auth = VNC_AUTH_SASL;
23265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_TLS
23275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->subauth = VNC_AUTH_INVALID;
23285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
23295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_TLS */
23305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_VNC_SASL */
23318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
23328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
23335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (tls) {
23345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->auth = VNC_AUTH_VENCRYPT;
23355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (x509) {
23365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
23375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
23385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
23395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
23405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
23415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
23425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
23438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
23445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            VNC_DEBUG("Initializing VNC server with no auth\n");
23455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->auth = VNC_AUTH_NONE;
23468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef CONFIG_VNC_TLS
23475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->subauth = VNC_AUTH_INVALID;
23485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
23498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
23508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
23515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
23525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VNC_SASL
23535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
23545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed to initialize SASL auth %s",
23555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                sasl_errstring(saslErr, NULL, NULL));
23565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        free(vs->display);
23575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vs->display = NULL;
23585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
23598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
23605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
23618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (reverse) {
23635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* connect to viewer */
23645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (strncmp(display, "unix:", 5) == 0)
23655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->lsock = unix_connect(display+5);
23665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        else
23675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->lsock = inet_connect(display, SOCK_STREAM);
23685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (-1 == vs->lsock) {
23695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            free(vs->display);
23705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->display = NULL;
23715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -1;
23725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
23735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int csock = vs->lsock;
23745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->lsock = -1;
23755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vnc_connect(vs, csock);
23768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
23778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
23788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
23795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
23805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* listen for connects */
23815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char *dpy;
23825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dpy = qemu_malloc(256);
23835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (strncmp(display, "unix:", 5) == 0) {
23845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            pstrcpy(dpy, 256, "unix:");
23855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->lsock = unix_listen(display+5, dpy+5, 256-5);
23865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
23875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
23885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
23895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (-1 == vs->lsock) {
23905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            free(dpy);
23915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -1;
23925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
23935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            free(vs->display);
23945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vs->display = dpy;
23955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
23968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
23975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
23988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2399