Statistics
| Branch: | Revision:

root / ui / vnc.c @ d4970b07

History | View | Annotate | Download (83.2 kB)

1 7d510b8c bellard
/*
2 7d510b8c bellard
 * QEMU VNC display driver
3 5fafdf24 ths
 *
4 7d510b8c bellard
 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5 7d510b8c bellard
 * Copyright (C) 2006 Fabrice Bellard
6 19a490bf aliguori
 * Copyright (C) 2009 Red Hat, Inc
7 5fafdf24 ths
 *
8 7d510b8c bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 7d510b8c bellard
 * of this software and associated documentation files (the "Software"), to deal
10 7d510b8c bellard
 * in the Software without restriction, including without limitation the rights
11 7d510b8c bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 7d510b8c bellard
 * copies of the Software, and to permit persons to whom the Software is
13 7d510b8c bellard
 * furnished to do so, subject to the following conditions:
14 7d510b8c bellard
 *
15 7d510b8c bellard
 * The above copyright notice and this permission notice shall be included in
16 7d510b8c bellard
 * all copies or substantial portions of the Software.
17 7d510b8c bellard
 *
18 7d510b8c bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 7d510b8c bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 7d510b8c bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 7d510b8c bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 7d510b8c bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 7d510b8c bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 7d510b8c bellard
 * THE SOFTWARE.
25 7d510b8c bellard
 */
26 7d510b8c bellard
27 19a490bf aliguori
#include "vnc.h"
28 bd023f95 Corentin Chary
#include "vnc-jobs.h"
29 87ecb68b pbrook
#include "sysemu.h"
30 6ca957f0 bellard
#include "qemu_socket.h"
31 87ecb68b pbrook
#include "qemu-timer.h"
32 76655d6d aliguori
#include "acl.h"
33 d96fd29c Luiz Capitulino
#include "qemu-objects.h"
34 24236869 bellard
35 2430ffe4 Stefano Stabellini
#define VNC_REFRESH_INTERVAL_BASE 30
36 2430ffe4 Stefano Stabellini
#define VNC_REFRESH_INTERVAL_INC  50
37 2430ffe4 Stefano Stabellini
#define VNC_REFRESH_INTERVAL_MAX  2000
38 999342a0 Corentin Chary
static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
39 999342a0 Corentin Chary
static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
40 24236869 bellard
41 24236869 bellard
#include "vnc_keysym.h"
42 70848515 ths
#include "d3des.h"
43 70848515 ths
44 753b4053 aliguori
static VncDisplay *vnc_display; /* needed for info vnc */
45 7d957bd8 aliguori
static DisplayChangeListener *dcl;
46 a9ce8590 bellard
47 d467b679 Gerd Hoffmann
static int vnc_cursor_define(VncState *vs);
48 d467b679 Gerd Hoffmann
49 1ff7df1a aliguori
static char *addr_to_string(const char *format,
50 1ff7df1a aliguori
                            struct sockaddr_storage *sa,
51 1ff7df1a aliguori
                            socklen_t salen) {
52 1ff7df1a aliguori
    char *addr;
53 1ff7df1a aliguori
    char host[NI_MAXHOST];
54 1ff7df1a aliguori
    char serv[NI_MAXSERV];
55 1ff7df1a aliguori
    int err;
56 457772e6 aliguori
    size_t addrlen;
57 1ff7df1a aliguori
58 1ff7df1a aliguori
    if ((err = getnameinfo((struct sockaddr *)sa, salen,
59 1ff7df1a aliguori
                           host, sizeof(host),
60 1ff7df1a aliguori
                           serv, sizeof(serv),
61 1ff7df1a aliguori
                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
62 1ff7df1a aliguori
        VNC_DEBUG("Cannot resolve address %d: %s\n",
63 1ff7df1a aliguori
                  err, gai_strerror(err));
64 1ff7df1a aliguori
        return NULL;
65 1ff7df1a aliguori
    }
66 1ff7df1a aliguori
67 457772e6 aliguori
    /* Enough for the existing format + the 2 vars we're
68 f425c278 Stefan Weil
     * substituting in. */
69 457772e6 aliguori
    addrlen = strlen(format) + strlen(host) + strlen(serv);
70 457772e6 aliguori
    addr = qemu_malloc(addrlen + 1);
71 457772e6 aliguori
    snprintf(addr, addrlen, format, host, serv);
72 457772e6 aliguori
    addr[addrlen] = '\0';
73 1ff7df1a aliguori
74 1ff7df1a aliguori
    return addr;
75 1ff7df1a aliguori
}
76 1ff7df1a aliguori
77 2f9606b3 aliguori
78 2f9606b3 aliguori
char *vnc_socket_local_addr(const char *format, int fd) {
79 1ff7df1a aliguori
    struct sockaddr_storage sa;
80 1ff7df1a aliguori
    socklen_t salen;
81 1ff7df1a aliguori
82 1ff7df1a aliguori
    salen = sizeof(sa);
83 1ff7df1a aliguori
    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
84 1ff7df1a aliguori
        return NULL;
85 1ff7df1a aliguori
86 1ff7df1a aliguori
    return addr_to_string(format, &sa, salen);
87 1ff7df1a aliguori
}
88 1ff7df1a aliguori
89 2f9606b3 aliguori
char *vnc_socket_remote_addr(const char *format, int fd) {
90 1ff7df1a aliguori
    struct sockaddr_storage sa;
91 1ff7df1a aliguori
    socklen_t salen;
92 1ff7df1a aliguori
93 1ff7df1a aliguori
    salen = sizeof(sa);
94 1ff7df1a aliguori
    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
95 1ff7df1a aliguori
        return NULL;
96 1ff7df1a aliguori
97 1ff7df1a aliguori
    return addr_to_string(format, &sa, salen);
98 1ff7df1a aliguori
}
99 1ff7df1a aliguori
100 d96fd29c Luiz Capitulino
static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa,
101 d96fd29c Luiz Capitulino
                          socklen_t salen)
102 d96fd29c Luiz Capitulino
{
103 d96fd29c Luiz Capitulino
    char host[NI_MAXHOST];
104 d96fd29c Luiz Capitulino
    char serv[NI_MAXSERV];
105 d96fd29c Luiz Capitulino
    int err;
106 d96fd29c Luiz Capitulino
107 d96fd29c Luiz Capitulino
    if ((err = getnameinfo((struct sockaddr *)sa, salen,
108 d96fd29c Luiz Capitulino
                           host, sizeof(host),
109 d96fd29c Luiz Capitulino
                           serv, sizeof(serv),
110 d96fd29c Luiz Capitulino
                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
111 d96fd29c Luiz Capitulino
        VNC_DEBUG("Cannot resolve address %d: %s\n",
112 d96fd29c Luiz Capitulino
                  err, gai_strerror(err));
113 d96fd29c Luiz Capitulino
        return -1;
114 d96fd29c Luiz Capitulino
    }
115 d96fd29c Luiz Capitulino
116 d96fd29c Luiz Capitulino
    qdict_put(qdict, "host", qstring_from_str(host));
117 d96fd29c Luiz Capitulino
    qdict_put(qdict, "service", qstring_from_str(serv));
118 dc0d4efc Luiz Capitulino
    qdict_put(qdict, "family",qstring_from_str(inet_strfamily(sa->ss_family)));
119 d96fd29c Luiz Capitulino
120 d96fd29c Luiz Capitulino
    return 0;
121 d96fd29c Luiz Capitulino
}
122 d96fd29c Luiz Capitulino
123 a7789382 Luiz Capitulino
static int vnc_server_addr_put(QDict *qdict, int fd)
124 d96fd29c Luiz Capitulino
{
125 d96fd29c Luiz Capitulino
    struct sockaddr_storage sa;
126 d96fd29c Luiz Capitulino
    socklen_t salen;
127 d96fd29c Luiz Capitulino
128 d96fd29c Luiz Capitulino
    salen = sizeof(sa);
129 d96fd29c Luiz Capitulino
    if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
130 d96fd29c Luiz Capitulino
        return -1;
131 d96fd29c Luiz Capitulino
    }
132 d96fd29c Luiz Capitulino
133 d96fd29c Luiz Capitulino
    return put_addr_qdict(qdict, &sa, salen);
134 d96fd29c Luiz Capitulino
}
135 d96fd29c Luiz Capitulino
136 d96fd29c Luiz Capitulino
static int vnc_qdict_remote_addr(QDict *qdict, int fd)
137 d96fd29c Luiz Capitulino
{
138 d96fd29c Luiz Capitulino
    struct sockaddr_storage sa;
139 d96fd29c Luiz Capitulino
    socklen_t salen;
140 d96fd29c Luiz Capitulino
141 d96fd29c Luiz Capitulino
    salen = sizeof(sa);
142 d96fd29c Luiz Capitulino
    if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
143 d96fd29c Luiz Capitulino
        return -1;
144 d96fd29c Luiz Capitulino
    }
145 d96fd29c Luiz Capitulino
146 d96fd29c Luiz Capitulino
    return put_addr_qdict(qdict, &sa, salen);
147 d96fd29c Luiz Capitulino
}
148 d96fd29c Luiz Capitulino
149 1ff7df1a aliguori
static const char *vnc_auth_name(VncDisplay *vd) {
150 1ff7df1a aliguori
    switch (vd->auth) {
151 1ff7df1a aliguori
    case VNC_AUTH_INVALID:
152 1ff7df1a aliguori
        return "invalid";
153 1ff7df1a aliguori
    case VNC_AUTH_NONE:
154 1ff7df1a aliguori
        return "none";
155 1ff7df1a aliguori
    case VNC_AUTH_VNC:
156 1ff7df1a aliguori
        return "vnc";
157 1ff7df1a aliguori
    case VNC_AUTH_RA2:
158 1ff7df1a aliguori
        return "ra2";
159 1ff7df1a aliguori
    case VNC_AUTH_RA2NE:
160 1ff7df1a aliguori
        return "ra2ne";
161 1ff7df1a aliguori
    case VNC_AUTH_TIGHT:
162 1ff7df1a aliguori
        return "tight";
163 1ff7df1a aliguori
    case VNC_AUTH_ULTRA:
164 1ff7df1a aliguori
        return "ultra";
165 1ff7df1a aliguori
    case VNC_AUTH_TLS:
166 1ff7df1a aliguori
        return "tls";
167 1ff7df1a aliguori
    case VNC_AUTH_VENCRYPT:
168 1ff7df1a aliguori
#ifdef CONFIG_VNC_TLS
169 1ff7df1a aliguori
        switch (vd->subauth) {
170 1ff7df1a aliguori
        case VNC_AUTH_VENCRYPT_PLAIN:
171 1ff7df1a aliguori
            return "vencrypt+plain";
172 1ff7df1a aliguori
        case VNC_AUTH_VENCRYPT_TLSNONE:
173 1ff7df1a aliguori
            return "vencrypt+tls+none";
174 1ff7df1a aliguori
        case VNC_AUTH_VENCRYPT_TLSVNC:
175 1ff7df1a aliguori
            return "vencrypt+tls+vnc";
176 1ff7df1a aliguori
        case VNC_AUTH_VENCRYPT_TLSPLAIN:
177 1ff7df1a aliguori
            return "vencrypt+tls+plain";
178 1ff7df1a aliguori
        case VNC_AUTH_VENCRYPT_X509NONE:
179 1ff7df1a aliguori
            return "vencrypt+x509+none";
180 1ff7df1a aliguori
        case VNC_AUTH_VENCRYPT_X509VNC:
181 1ff7df1a aliguori
            return "vencrypt+x509+vnc";
182 1ff7df1a aliguori
        case VNC_AUTH_VENCRYPT_X509PLAIN:
183 1ff7df1a aliguori
            return "vencrypt+x509+plain";
184 28a76be8 aliguori
        case VNC_AUTH_VENCRYPT_TLSSASL:
185 28a76be8 aliguori
            return "vencrypt+tls+sasl";
186 28a76be8 aliguori
        case VNC_AUTH_VENCRYPT_X509SASL:
187 28a76be8 aliguori
            return "vencrypt+x509+sasl";
188 1ff7df1a aliguori
        default:
189 1ff7df1a aliguori
            return "vencrypt";
190 1ff7df1a aliguori
        }
191 1ff7df1a aliguori
#else
192 1ff7df1a aliguori
        return "vencrypt";
193 1ff7df1a aliguori
#endif
194 2f9606b3 aliguori
    case VNC_AUTH_SASL:
195 28a76be8 aliguori
        return "sasl";
196 1ff7df1a aliguori
    }
197 1ff7df1a aliguori
    return "unknown";
198 1ff7df1a aliguori
}
199 1ff7df1a aliguori
200 a7789382 Luiz Capitulino
static int vnc_server_info_put(QDict *qdict)
201 a7789382 Luiz Capitulino
{
202 a7789382 Luiz Capitulino
    if (vnc_server_addr_put(qdict, vnc_display->lsock) < 0) {
203 a7789382 Luiz Capitulino
        return -1;
204 a7789382 Luiz Capitulino
    }
205 a7789382 Luiz Capitulino
206 a7789382 Luiz Capitulino
    qdict_put(qdict, "auth", qstring_from_str(vnc_auth_name(vnc_display)));
207 a7789382 Luiz Capitulino
    return 0;
208 a7789382 Luiz Capitulino
}
209 a7789382 Luiz Capitulino
210 4a80dba3 Luiz Capitulino
static void vnc_client_cache_auth(VncState *client)
211 1ff7df1a aliguori
{
212 2ded6ad7 Blue Swirl
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
213 d96fd29c Luiz Capitulino
    QDict *qdict;
214 2ded6ad7 Blue Swirl
#endif
215 1ff7df1a aliguori
216 4a80dba3 Luiz Capitulino
    if (!client->info) {
217 4a80dba3 Luiz Capitulino
        return;
218 d96fd29c Luiz Capitulino
    }
219 1263b7d6 aliguori
220 2ded6ad7 Blue Swirl
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
221 4a80dba3 Luiz Capitulino
    qdict = qobject_to_qdict(client->info);
222 2ded6ad7 Blue Swirl
#endif
223 4a80dba3 Luiz Capitulino
224 1263b7d6 aliguori
#ifdef CONFIG_VNC_TLS
225 1263b7d6 aliguori
    if (client->tls.session &&
226 d96fd29c Luiz Capitulino
        client->tls.dname) {
227 d96fd29c Luiz Capitulino
        qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname));
228 d96fd29c Luiz Capitulino
    }
229 1263b7d6 aliguori
#endif
230 1263b7d6 aliguori
#ifdef CONFIG_VNC_SASL
231 1263b7d6 aliguori
    if (client->sasl.conn &&
232 d96fd29c Luiz Capitulino
        client->sasl.username) {
233 76825067 Luiz Capitulino
        qdict_put(qdict, "sasl_username",
234 76825067 Luiz Capitulino
                  qstring_from_str(client->sasl.username));
235 d96fd29c Luiz Capitulino
    }
236 1263b7d6 aliguori
#endif
237 4a80dba3 Luiz Capitulino
}
238 d96fd29c Luiz Capitulino
239 4a80dba3 Luiz Capitulino
static void vnc_client_cache_addr(VncState *client)
240 4a80dba3 Luiz Capitulino
{
241 4a80dba3 Luiz Capitulino
    QDict *qdict;
242 4a80dba3 Luiz Capitulino
243 4a80dba3 Luiz Capitulino
    qdict = qdict_new();
244 4a80dba3 Luiz Capitulino
    if (vnc_qdict_remote_addr(qdict, client->csock) < 0) {
245 4a80dba3 Luiz Capitulino
        QDECREF(qdict);
246 4a80dba3 Luiz Capitulino
        /* XXX: how to report the error? */
247 4a80dba3 Luiz Capitulino
        return;
248 4a80dba3 Luiz Capitulino
    }
249 4a80dba3 Luiz Capitulino
250 4a80dba3 Luiz Capitulino
    client->info = QOBJECT(qdict);
251 1ff7df1a aliguori
}
252 1ff7df1a aliguori
253 586153d9 Luiz Capitulino
static void vnc_qmp_event(VncState *vs, MonitorEvent event)
254 586153d9 Luiz Capitulino
{
255 586153d9 Luiz Capitulino
    QDict *server;
256 586153d9 Luiz Capitulino
    QObject *data;
257 586153d9 Luiz Capitulino
258 586153d9 Luiz Capitulino
    if (!vs->info) {
259 586153d9 Luiz Capitulino
        return;
260 586153d9 Luiz Capitulino
    }
261 586153d9 Luiz Capitulino
262 586153d9 Luiz Capitulino
    server = qdict_new();
263 586153d9 Luiz Capitulino
    if (vnc_server_info_put(server) < 0) {
264 586153d9 Luiz Capitulino
        QDECREF(server);
265 586153d9 Luiz Capitulino
        return;
266 586153d9 Luiz Capitulino
    }
267 586153d9 Luiz Capitulino
268 586153d9 Luiz Capitulino
    data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
269 586153d9 Luiz Capitulino
                              vs->info, QOBJECT(server));
270 586153d9 Luiz Capitulino
271 586153d9 Luiz Capitulino
    monitor_protocol_event(event, data);
272 586153d9 Luiz Capitulino
273 586153d9 Luiz Capitulino
    qobject_incref(vs->info);
274 586153d9 Luiz Capitulino
    qobject_decref(data);
275 586153d9 Luiz Capitulino
}
276 586153d9 Luiz Capitulino
277 d96fd29c Luiz Capitulino
static void info_vnc_iter(QObject *obj, void *opaque)
278 a9ce8590 bellard
{
279 d96fd29c Luiz Capitulino
    QDict *client;
280 d96fd29c Luiz Capitulino
    Monitor *mon = opaque;
281 d96fd29c Luiz Capitulino
282 d96fd29c Luiz Capitulino
    client = qobject_to_qdict(obj);
283 d96fd29c Luiz Capitulino
    monitor_printf(mon, "Client:\n");
284 d96fd29c Luiz Capitulino
    monitor_printf(mon, "     address: %s:%s\n",
285 d96fd29c Luiz Capitulino
                   qdict_get_str(client, "host"),
286 d96fd29c Luiz Capitulino
                   qdict_get_str(client, "service"));
287 d96fd29c Luiz Capitulino
288 d96fd29c Luiz Capitulino
#ifdef CONFIG_VNC_TLS
289 d96fd29c Luiz Capitulino
    monitor_printf(mon, "  x509_dname: %s\n",
290 d96fd29c Luiz Capitulino
        qdict_haskey(client, "x509_dname") ?
291 d96fd29c Luiz Capitulino
        qdict_get_str(client, "x509_dname") : "none");
292 d96fd29c Luiz Capitulino
#endif
293 d96fd29c Luiz Capitulino
#ifdef CONFIG_VNC_SASL
294 d96fd29c Luiz Capitulino
    monitor_printf(mon, "    username: %s\n",
295 76825067 Luiz Capitulino
        qdict_haskey(client, "sasl_username") ?
296 76825067 Luiz Capitulino
        qdict_get_str(client, "sasl_username") : "none");
297 d96fd29c Luiz Capitulino
#endif
298 d96fd29c Luiz Capitulino
}
299 d96fd29c Luiz Capitulino
300 d96fd29c Luiz Capitulino
void do_info_vnc_print(Monitor *mon, const QObject *data)
301 d96fd29c Luiz Capitulino
{
302 d96fd29c Luiz Capitulino
    QDict *server;
303 d96fd29c Luiz Capitulino
    QList *clients;
304 d96fd29c Luiz Capitulino
305 d96fd29c Luiz Capitulino
    server = qobject_to_qdict(data);
306 8950a950 Luiz Capitulino
    if (qdict_get_bool(server, "enabled") == 0) {
307 1ff7df1a aliguori
        monitor_printf(mon, "Server: disabled\n");
308 d96fd29c Luiz Capitulino
        return;
309 d96fd29c Luiz Capitulino
    }
310 1ff7df1a aliguori
311 d96fd29c Luiz Capitulino
    monitor_printf(mon, "Server:\n");
312 d96fd29c Luiz Capitulino
    monitor_printf(mon, "     address: %s:%s\n",
313 d96fd29c Luiz Capitulino
                   qdict_get_str(server, "host"),
314 d96fd29c Luiz Capitulino
                   qdict_get_str(server, "service"));
315 a7789382 Luiz Capitulino
    monitor_printf(mon, "        auth: %s\n", qdict_get_str(server, "auth"));
316 d96fd29c Luiz Capitulino
317 d96fd29c Luiz Capitulino
    clients = qdict_get_qlist(server, "clients");
318 d96fd29c Luiz Capitulino
    if (qlist_empty(clients)) {
319 d96fd29c Luiz Capitulino
        monitor_printf(mon, "Client: none\n");
320 d96fd29c Luiz Capitulino
    } else {
321 d96fd29c Luiz Capitulino
        qlist_iter(clients, info_vnc_iter, mon);
322 d96fd29c Luiz Capitulino
    }
323 d96fd29c Luiz Capitulino
}
324 1ff7df1a aliguori
325 d96fd29c Luiz Capitulino
void do_info_vnc(Monitor *mon, QObject **ret_data)
326 d96fd29c Luiz Capitulino
{
327 d96fd29c Luiz Capitulino
    if (vnc_display == NULL || vnc_display->display == NULL) {
328 8950a950 Luiz Capitulino
        *ret_data = qobject_from_jsonf("{ 'enabled': false }");
329 d96fd29c Luiz Capitulino
    } else {
330 d96fd29c Luiz Capitulino
        QList *clist;
331 41b4bef6 Amit Shah
        VncState *client;
332 1ff7df1a aliguori
333 d96fd29c Luiz Capitulino
        clist = qlist_new();
334 41b4bef6 Amit Shah
        QTAILQ_FOREACH(client, &vnc_display->clients, next) {
335 41b4bef6 Amit Shah
            if (client->info) {
336 41b4bef6 Amit Shah
                /* incref so that it's not freed by upper layers */
337 41b4bef6 Amit Shah
                qobject_incref(client->info);
338 41b4bef6 Amit Shah
                qlist_append_obj(clist, client->info);
339 1ff7df1a aliguori
            }
340 d96fd29c Luiz Capitulino
        }
341 d96fd29c Luiz Capitulino
342 8950a950 Luiz Capitulino
        *ret_data = qobject_from_jsonf("{ 'enabled': true, 'clients': %p }",
343 d96fd29c Luiz Capitulino
                                       QOBJECT(clist));
344 d96fd29c Luiz Capitulino
        assert(*ret_data != NULL);
345 d96fd29c Luiz Capitulino
346 a7789382 Luiz Capitulino
        if (vnc_server_info_put(qobject_to_qdict(*ret_data)) < 0) {
347 d96fd29c Luiz Capitulino
            qobject_decref(*ret_data);
348 d96fd29c Luiz Capitulino
            *ret_data = NULL;
349 1ff7df1a aliguori
        }
350 a9ce8590 bellard
    }
351 a9ce8590 bellard
}
352 a9ce8590 bellard
353 24236869 bellard
/* TODO
354 24236869 bellard
   1) Get the queue working for IO.
355 24236869 bellard
   2) there is some weirdness when using the -S option (the screen is grey
356 24236869 bellard
      and not totally invalidated
357 24236869 bellard
   3) resolutions > 1024
358 24236869 bellard
*/
359 24236869 bellard
360 2430ffe4 Stefano Stabellini
static int vnc_update_client(VncState *vs, int has_dirty);
361 bd023f95 Corentin Chary
static int vnc_update_client_sync(VncState *vs, int has_dirty);
362 198a0039 Gerd Hoffmann
static void vnc_disconnect_start(VncState *vs);
363 198a0039 Gerd Hoffmann
static void vnc_disconnect_finish(VncState *vs);
364 703bc68f Stefano Stabellini
static void vnc_init_timer(VncDisplay *vd);
365 703bc68f Stefano Stabellini
static void vnc_remove_timer(VncDisplay *vd);
366 24236869 bellard
367 753b4053 aliguori
static void vnc_colordepth(VncState *vs);
368 1fc62412 Stefano Stabellini
static void framebuffer_update_request(VncState *vs, int incremental,
369 1fc62412 Stefano Stabellini
                                       int x_position, int y_position,
370 1fc62412 Stefano Stabellini
                                       int w, int h);
371 1fc62412 Stefano Stabellini
static void vnc_refresh(void *opaque);
372 1fc62412 Stefano Stabellini
static int vnc_refresh_server_surface(VncDisplay *vd);
373 7eac3a87 aliguori
374 1fc62412 Stefano Stabellini
static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
375 24236869 bellard
{
376 24236869 bellard
    int i;
377 1fc62412 Stefano Stabellini
    VncDisplay *vd = ds->opaque;
378 1fc62412 Stefano Stabellini
    struct VncSurface *s = &vd->guest;
379 24236869 bellard
380 24236869 bellard
    h += y;
381 24236869 bellard
382 0486e8a7 balrog
    /* round x down to ensure the loop only spans one 16-pixel block per,
383 0486e8a7 balrog
       iteration.  otherwise, if (x % 16) != 0, the last iteration may span
384 0486e8a7 balrog
       two 16-pixel blocks but we only mark the first as dirty
385 0486e8a7 balrog
    */
386 0486e8a7 balrog
    w += (x % 16);
387 0486e8a7 balrog
    x -= (x % 16);
388 0486e8a7 balrog
389 6baebed7 aliguori
    x = MIN(x, s->ds->width);
390 6baebed7 aliguori
    y = MIN(y, s->ds->height);
391 6baebed7 aliguori
    w = MIN(x + w, s->ds->width) - x;
392 6baebed7 aliguori
    h = MIN(h, s->ds->height);
393 788abf8e balrog
394 24236869 bellard
    for (; y < h; y++)
395 28a76be8 aliguori
        for (i = 0; i < w; i += 16)
396 bc2429b9 Corentin Chary
            set_bit((x + i) / 16, s->dirty[y]);
397 24236869 bellard
}
398 24236869 bellard
399 70a4568f Corentin Chary
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
400 70a4568f Corentin Chary
                            int32_t encoding)
401 24236869 bellard
{
402 24236869 bellard
    vnc_write_u16(vs, x);
403 24236869 bellard
    vnc_write_u16(vs, y);
404 24236869 bellard
    vnc_write_u16(vs, w);
405 24236869 bellard
    vnc_write_u16(vs, h);
406 24236869 bellard
407 24236869 bellard
    vnc_write_s32(vs, encoding);
408 24236869 bellard
}
409 24236869 bellard
410 2f9606b3 aliguori
void buffer_reserve(Buffer *buffer, size_t len)
411 89064286 aliguori
{
412 89064286 aliguori
    if ((buffer->capacity - buffer->offset) < len) {
413 28a76be8 aliguori
        buffer->capacity += (len + 1024);
414 28a76be8 aliguori
        buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity);
415 28a76be8 aliguori
        if (buffer->buffer == NULL) {
416 28a76be8 aliguori
            fprintf(stderr, "vnc: out of memory\n");
417 28a76be8 aliguori
            exit(1);
418 28a76be8 aliguori
        }
419 89064286 aliguori
    }
420 89064286 aliguori
}
421 89064286 aliguori
422 2f9606b3 aliguori
int buffer_empty(Buffer *buffer)
423 89064286 aliguori
{
424 89064286 aliguori
    return buffer->offset == 0;
425 89064286 aliguori
}
426 89064286 aliguori
427 2f9606b3 aliguori
uint8_t *buffer_end(Buffer *buffer)
428 89064286 aliguori
{
429 89064286 aliguori
    return buffer->buffer + buffer->offset;
430 89064286 aliguori
}
431 89064286 aliguori
432 2f9606b3 aliguori
void buffer_reset(Buffer *buffer)
433 89064286 aliguori
{
434 28a76be8 aliguori
        buffer->offset = 0;
435 89064286 aliguori
}
436 89064286 aliguori
437 5d418e3b Corentin Chary
void buffer_free(Buffer *buffer)
438 5d418e3b Corentin Chary
{
439 5d418e3b Corentin Chary
    qemu_free(buffer->buffer);
440 5d418e3b Corentin Chary
    buffer->offset = 0;
441 5d418e3b Corentin Chary
    buffer->capacity = 0;
442 5d418e3b Corentin Chary
    buffer->buffer = NULL;
443 5d418e3b Corentin Chary
}
444 5d418e3b Corentin Chary
445 2f9606b3 aliguori
void buffer_append(Buffer *buffer, const void *data, size_t len)
446 89064286 aliguori
{
447 89064286 aliguori
    memcpy(buffer->buffer + buffer->offset, data, len);
448 89064286 aliguori
    buffer->offset += len;
449 89064286 aliguori
}
450 89064286 aliguori
451 621aaeb9 Gerd Hoffmann
static void vnc_desktop_resize(VncState *vs)
452 621aaeb9 Gerd Hoffmann
{
453 621aaeb9 Gerd Hoffmann
    DisplayState *ds = vs->ds;
454 621aaeb9 Gerd Hoffmann
455 621aaeb9 Gerd Hoffmann
    if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
456 621aaeb9 Gerd Hoffmann
        return;
457 621aaeb9 Gerd Hoffmann
    }
458 1d4b638a Gerd Hoffmann
    if (vs->client_width == ds_get_width(ds) &&
459 1d4b638a Gerd Hoffmann
        vs->client_height == ds_get_height(ds)) {
460 1d4b638a Gerd Hoffmann
        return;
461 1d4b638a Gerd Hoffmann
    }
462 5862d195 Gerd Hoffmann
    vs->client_width = ds_get_width(ds);
463 5862d195 Gerd Hoffmann
    vs->client_height = ds_get_height(ds);
464 bd023f95 Corentin Chary
    vnc_lock_output(vs);
465 621aaeb9 Gerd Hoffmann
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
466 621aaeb9 Gerd Hoffmann
    vnc_write_u8(vs, 0);
467 621aaeb9 Gerd Hoffmann
    vnc_write_u16(vs, 1); /* number of rects */
468 5862d195 Gerd Hoffmann
    vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
469 621aaeb9 Gerd Hoffmann
                           VNC_ENCODING_DESKTOPRESIZE);
470 bd023f95 Corentin Chary
    vnc_unlock_output(vs);
471 621aaeb9 Gerd Hoffmann
    vnc_flush(vs);
472 621aaeb9 Gerd Hoffmann
}
473 621aaeb9 Gerd Hoffmann
474 bd023f95 Corentin Chary
#ifdef CONFIG_VNC_THREAD
475 bd023f95 Corentin Chary
static void vnc_abort_display_jobs(VncDisplay *vd)
476 bd023f95 Corentin Chary
{
477 bd023f95 Corentin Chary
    VncState *vs;
478 bd023f95 Corentin Chary
479 bd023f95 Corentin Chary
    QTAILQ_FOREACH(vs, &vd->clients, next) {
480 bd023f95 Corentin Chary
        vnc_lock_output(vs);
481 bd023f95 Corentin Chary
        vs->abort = true;
482 bd023f95 Corentin Chary
        vnc_unlock_output(vs);
483 bd023f95 Corentin Chary
    }
484 bd023f95 Corentin Chary
    QTAILQ_FOREACH(vs, &vd->clients, next) {
485 bd023f95 Corentin Chary
        vnc_jobs_join(vs);
486 bd023f95 Corentin Chary
    }
487 bd023f95 Corentin Chary
    QTAILQ_FOREACH(vs, &vd->clients, next) {
488 bd023f95 Corentin Chary
        vnc_lock_output(vs);
489 bd023f95 Corentin Chary
        vs->abort = false;
490 bd023f95 Corentin Chary
        vnc_unlock_output(vs);
491 bd023f95 Corentin Chary
    }
492 bd023f95 Corentin Chary
}
493 bd023f95 Corentin Chary
#else
494 bd023f95 Corentin Chary
static void vnc_abort_display_jobs(VncDisplay *vd)
495 bd023f95 Corentin Chary
{
496 bd023f95 Corentin Chary
}
497 bd023f95 Corentin Chary
#endif
498 bd023f95 Corentin Chary
499 1fc62412 Stefano Stabellini
static void vnc_dpy_resize(DisplayState *ds)
500 24236869 bellard
{
501 1fc62412 Stefano Stabellini
    VncDisplay *vd = ds->opaque;
502 41b4bef6 Amit Shah
    VncState *vs;
503 1fc62412 Stefano Stabellini
504 bd023f95 Corentin Chary
    vnc_abort_display_jobs(vd);
505 bd023f95 Corentin Chary
506 1fc62412 Stefano Stabellini
    /* server surface */
507 1fc62412 Stefano Stabellini
    if (!vd->server)
508 1fc62412 Stefano Stabellini
        vd->server = qemu_mallocz(sizeof(*vd->server));
509 1fc62412 Stefano Stabellini
    if (vd->server->data)
510 1fc62412 Stefano Stabellini
        qemu_free(vd->server->data);
511 1fc62412 Stefano Stabellini
    *(vd->server) = *(ds->surface);
512 1fc62412 Stefano Stabellini
    vd->server->data = qemu_mallocz(vd->server->linesize *
513 1fc62412 Stefano Stabellini
                                    vd->server->height);
514 24236869 bellard
515 6baebed7 aliguori
    /* guest surface */
516 1fc62412 Stefano Stabellini
    if (!vd->guest.ds)
517 1fc62412 Stefano Stabellini
        vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
518 1fc62412 Stefano Stabellini
    if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
519 a528b80c balrog
        console_color_init(ds);
520 1fc62412 Stefano Stabellini
    *(vd->guest.ds) = *(ds->surface);
521 1fc62412 Stefano Stabellini
    memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
522 24236869 bellard
523 41b4bef6 Amit Shah
    QTAILQ_FOREACH(vs, &vd->clients, next) {
524 1fc62412 Stefano Stabellini
        vnc_colordepth(vs);
525 1d4b638a Gerd Hoffmann
        vnc_desktop_resize(vs);
526 d467b679 Gerd Hoffmann
        if (vs->vd->cursor) {
527 d467b679 Gerd Hoffmann
            vnc_cursor_define(vs);
528 d467b679 Gerd Hoffmann
        }
529 1fc62412 Stefano Stabellini
        memset(vs->dirty, 0xFF, sizeof(vs->dirty));
530 753b4053 aliguori
    }
531 753b4053 aliguori
}
532 753b4053 aliguori
533 3512779a bellard
/* fastest code */
534 d467b679 Gerd Hoffmann
static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf,
535 d467b679 Gerd Hoffmann
                                  void *pixels, int size)
536 3512779a bellard
{
537 3512779a bellard
    vnc_write(vs, pixels, size);
538 3512779a bellard
}
539 3512779a bellard
540 3512779a bellard
/* slowest but generic code. */
541 70a4568f Corentin Chary
void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
542 3512779a bellard
{
543 7eac3a87 aliguori
    uint8_t r, g, b;
544 1fc62412 Stefano Stabellini
    VncDisplay *vd = vs->vd;
545 1fc62412 Stefano Stabellini
546 1fc62412 Stefano Stabellini
    r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >>
547 1fc62412 Stefano Stabellini
        vd->server->pf.rbits);
548 1fc62412 Stefano Stabellini
    g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >>
549 1fc62412 Stefano Stabellini
        vd->server->pf.gbits);
550 1fc62412 Stefano Stabellini
    b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >>
551 1fc62412 Stefano Stabellini
        vd->server->pf.bbits);
552 6cec5487 aliguori
    v = (r << vs->clientds.pf.rshift) |
553 6cec5487 aliguori
        (g << vs->clientds.pf.gshift) |
554 6cec5487 aliguori
        (b << vs->clientds.pf.bshift);
555 6cec5487 aliguori
    switch(vs->clientds.pf.bytes_per_pixel) {
556 3512779a bellard
    case 1:
557 3512779a bellard
        buf[0] = v;
558 3512779a bellard
        break;
559 3512779a bellard
    case 2:
560 6cec5487 aliguori
        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
561 3512779a bellard
            buf[0] = v >> 8;
562 3512779a bellard
            buf[1] = v;
563 3512779a bellard
        } else {
564 3512779a bellard
            buf[1] = v >> 8;
565 3512779a bellard
            buf[0] = v;
566 3512779a bellard
        }
567 3512779a bellard
        break;
568 3512779a bellard
    default:
569 3512779a bellard
    case 4:
570 6cec5487 aliguori
        if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
571 3512779a bellard
            buf[0] = v >> 24;
572 3512779a bellard
            buf[1] = v >> 16;
573 3512779a bellard
            buf[2] = v >> 8;
574 3512779a bellard
            buf[3] = v;
575 3512779a bellard
        } else {
576 3512779a bellard
            buf[3] = v >> 24;
577 3512779a bellard
            buf[2] = v >> 16;
578 3512779a bellard
            buf[1] = v >> 8;
579 3512779a bellard
            buf[0] = v;
580 3512779a bellard
        }
581 3512779a bellard
        break;
582 3512779a bellard
    }
583 3512779a bellard
}
584 3512779a bellard
585 d467b679 Gerd Hoffmann
static void vnc_write_pixels_generic(VncState *vs, struct PixelFormat *pf,
586 d467b679 Gerd Hoffmann
                                     void *pixels1, int size)
587 3512779a bellard
{
588 3512779a bellard
    uint8_t buf[4];
589 3512779a bellard
590 d467b679 Gerd Hoffmann
    if (pf->bytes_per_pixel == 4) {
591 7eac3a87 aliguori
        uint32_t *pixels = pixels1;
592 7eac3a87 aliguori
        int n, i;
593 7eac3a87 aliguori
        n = size >> 2;
594 7eac3a87 aliguori
        for(i = 0; i < n; i++) {
595 7eac3a87 aliguori
            vnc_convert_pixel(vs, buf, pixels[i]);
596 6cec5487 aliguori
            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
597 7eac3a87 aliguori
        }
598 d467b679 Gerd Hoffmann
    } else if (pf->bytes_per_pixel == 2) {
599 7eac3a87 aliguori
        uint16_t *pixels = pixels1;
600 7eac3a87 aliguori
        int n, i;
601 7eac3a87 aliguori
        n = size >> 1;
602 7eac3a87 aliguori
        for(i = 0; i < n; i++) {
603 7eac3a87 aliguori
            vnc_convert_pixel(vs, buf, pixels[i]);
604 6cec5487 aliguori
            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
605 7eac3a87 aliguori
        }
606 d467b679 Gerd Hoffmann
    } else if (pf->bytes_per_pixel == 1) {
607 7eac3a87 aliguori
        uint8_t *pixels = pixels1;
608 7eac3a87 aliguori
        int n, i;
609 7eac3a87 aliguori
        n = size;
610 7eac3a87 aliguori
        for(i = 0; i < n; i++) {
611 7eac3a87 aliguori
            vnc_convert_pixel(vs, buf, pixels[i]);
612 6cec5487 aliguori
            vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
613 7eac3a87 aliguori
        }
614 7eac3a87 aliguori
    } else {
615 7eac3a87 aliguori
        fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
616 3512779a bellard
    }
617 3512779a bellard
}
618 3512779a bellard
619 a885211e Corentin Chary
int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
620 24236869 bellard
{
621 24236869 bellard
    int i;
622 60fe76f3 ths
    uint8_t *row;
623 1fc62412 Stefano Stabellini
    VncDisplay *vd = vs->vd;
624 24236869 bellard
625 1fc62412 Stefano Stabellini
    row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
626 24236869 bellard
    for (i = 0; i < h; i++) {
627 d467b679 Gerd Hoffmann
        vs->write_pixels(vs, &vd->server->pf, row, w * ds_get_bytes_per_pixel(vs->ds));
628 28a76be8 aliguori
        row += ds_get_linesize(vs->ds);
629 24236869 bellard
    }
630 a885211e Corentin Chary
    return 1;
631 24236869 bellard
}
632 24236869 bellard
633 bd023f95 Corentin Chary
int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
634 24236869 bellard
{
635 a885211e Corentin Chary
    int n = 0;
636 a885211e Corentin Chary
637 fb437313 aliguori
    switch(vs->vnc_encoding) {
638 28a76be8 aliguori
        case VNC_ENCODING_ZLIB:
639 a885211e Corentin Chary
            n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h);
640 28a76be8 aliguori
            break;
641 28a76be8 aliguori
        case VNC_ENCODING_HEXTILE:
642 28a76be8 aliguori
            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE);
643 a885211e Corentin Chary
            n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h);
644 28a76be8 aliguori
            break;
645 380282b0 Corentin Chary
        case VNC_ENCODING_TIGHT:
646 380282b0 Corentin Chary
            n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
647 380282b0 Corentin Chary
            break;
648 efe556ad Corentin Chary
        case VNC_ENCODING_TIGHT_PNG:
649 efe556ad Corentin Chary
            n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
650 efe556ad Corentin Chary
            break;
651 148954fa Corentin Chary
        case VNC_ENCODING_ZRLE:
652 148954fa Corentin Chary
            n = vnc_zrle_send_framebuffer_update(vs, x, y, w, h);
653 148954fa Corentin Chary
            break;
654 148954fa Corentin Chary
        case VNC_ENCODING_ZYWRLE:
655 148954fa Corentin Chary
            n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
656 148954fa Corentin Chary
            break;
657 28a76be8 aliguori
        default:
658 28a76be8 aliguori
            vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
659 a885211e Corentin Chary
            n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
660 28a76be8 aliguori
            break;
661 fb437313 aliguori
    }
662 a885211e Corentin Chary
    return n;
663 24236869 bellard
}
664 24236869 bellard
665 753b4053 aliguori
static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
666 24236869 bellard
{
667 3e28c9ad Gerd Hoffmann
    /* send bitblit op to the vnc client */
668 bd023f95 Corentin Chary
    vnc_lock_output(vs);
669 46a183da Daniel P. Berrange
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
670 24236869 bellard
    vnc_write_u8(vs, 0);
671 24236869 bellard
    vnc_write_u16(vs, 1); /* number of rects */
672 29fa4ed9 aliguori
    vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
673 24236869 bellard
    vnc_write_u16(vs, src_x);
674 24236869 bellard
    vnc_write_u16(vs, src_y);
675 bd023f95 Corentin Chary
    vnc_unlock_output(vs);
676 24236869 bellard
    vnc_flush(vs);
677 24236869 bellard
}
678 24236869 bellard
679 753b4053 aliguori
static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
680 753b4053 aliguori
{
681 753b4053 aliguori
    VncDisplay *vd = ds->opaque;
682 198a0039 Gerd Hoffmann
    VncState *vs, *vn;
683 1fc62412 Stefano Stabellini
    uint8_t *src_row;
684 1fc62412 Stefano Stabellini
    uint8_t *dst_row;
685 1fc62412 Stefano Stabellini
    int i,x,y,pitch,depth,inc,w_lim,s;
686 1fc62412 Stefano Stabellini
    int cmp_bytes;
687 198a0039 Gerd Hoffmann
688 1fc62412 Stefano Stabellini
    vnc_refresh_server_surface(vd);
689 41b4bef6 Amit Shah
    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
690 198a0039 Gerd Hoffmann
        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
691 198a0039 Gerd Hoffmann
            vs->force_update = 1;
692 bd023f95 Corentin Chary
            vnc_update_client_sync(vs, 1);
693 198a0039 Gerd Hoffmann
            /* vs might be free()ed here */
694 198a0039 Gerd Hoffmann
        }
695 198a0039 Gerd Hoffmann
    }
696 198a0039 Gerd Hoffmann
697 1fc62412 Stefano Stabellini
    /* do bitblit op on the local surface too */
698 1fc62412 Stefano Stabellini
    pitch = ds_get_linesize(vd->ds);
699 1fc62412 Stefano Stabellini
    depth = ds_get_bytes_per_pixel(vd->ds);
700 1fc62412 Stefano Stabellini
    src_row = vd->server->data + pitch * src_y + depth * src_x;
701 1fc62412 Stefano Stabellini
    dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
702 1fc62412 Stefano Stabellini
    y = dst_y;
703 1fc62412 Stefano Stabellini
    inc = 1;
704 1fc62412 Stefano Stabellini
    if (dst_y > src_y) {
705 1fc62412 Stefano Stabellini
        /* copy backwards */
706 1fc62412 Stefano Stabellini
        src_row += pitch * (h-1);
707 1fc62412 Stefano Stabellini
        dst_row += pitch * (h-1);
708 1fc62412 Stefano Stabellini
        pitch = -pitch;
709 1fc62412 Stefano Stabellini
        y = dst_y + h - 1;
710 1fc62412 Stefano Stabellini
        inc = -1;
711 1fc62412 Stefano Stabellini
    }
712 1fc62412 Stefano Stabellini
    w_lim = w - (16 - (dst_x % 16));
713 1fc62412 Stefano Stabellini
    if (w_lim < 0)
714 1fc62412 Stefano Stabellini
        w_lim = w;
715 1fc62412 Stefano Stabellini
    else
716 1fc62412 Stefano Stabellini
        w_lim = w - (w_lim % 16);
717 1fc62412 Stefano Stabellini
    for (i = 0; i < h; i++) {
718 1fc62412 Stefano Stabellini
        for (x = 0; x <= w_lim;
719 1fc62412 Stefano Stabellini
                x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
720 1fc62412 Stefano Stabellini
            if (x == w_lim) {
721 1fc62412 Stefano Stabellini
                if ((s = w - w_lim) == 0)
722 1fc62412 Stefano Stabellini
                    break;
723 1fc62412 Stefano Stabellini
            } else if (!x) {
724 1fc62412 Stefano Stabellini
                s = (16 - (dst_x % 16));
725 1fc62412 Stefano Stabellini
                s = MIN(s, w_lim);
726 1fc62412 Stefano Stabellini
            } else {
727 1fc62412 Stefano Stabellini
                s = 16;
728 1fc62412 Stefano Stabellini
            }
729 1fc62412 Stefano Stabellini
            cmp_bytes = s * depth;
730 1fc62412 Stefano Stabellini
            if (memcmp(src_row, dst_row, cmp_bytes) == 0)
731 1fc62412 Stefano Stabellini
                continue;
732 1fc62412 Stefano Stabellini
            memmove(dst_row, src_row, cmp_bytes);
733 41b4bef6 Amit Shah
            QTAILQ_FOREACH(vs, &vd->clients, next) {
734 41b4bef6 Amit Shah
                if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
735 bc2429b9 Corentin Chary
                    set_bit(((x + dst_x) / 16), vs->dirty[y]);
736 41b4bef6 Amit Shah
                }
737 1fc62412 Stefano Stabellini
            }
738 1fc62412 Stefano Stabellini
        }
739 1fc62412 Stefano Stabellini
        src_row += pitch - w * depth;
740 1fc62412 Stefano Stabellini
        dst_row += pitch - w * depth;
741 1fc62412 Stefano Stabellini
        y += inc;
742 1fc62412 Stefano Stabellini
    }
743 1fc62412 Stefano Stabellini
744 41b4bef6 Amit Shah
    QTAILQ_FOREACH(vs, &vd->clients, next) {
745 41b4bef6 Amit Shah
        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
746 753b4053 aliguori
            vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
747 41b4bef6 Amit Shah
        }
748 753b4053 aliguori
    }
749 753b4053 aliguori
}
750 753b4053 aliguori
751 d467b679 Gerd Hoffmann
static void vnc_mouse_set(int x, int y, int visible)
752 d467b679 Gerd Hoffmann
{
753 d467b679 Gerd Hoffmann
    /* can we ask the client(s) to move the pointer ??? */
754 d467b679 Gerd Hoffmann
}
755 d467b679 Gerd Hoffmann
756 d467b679 Gerd Hoffmann
static int vnc_cursor_define(VncState *vs)
757 d467b679 Gerd Hoffmann
{
758 d467b679 Gerd Hoffmann
    QEMUCursor *c = vs->vd->cursor;
759 d467b679 Gerd Hoffmann
    PixelFormat pf = qemu_default_pixelformat(32);
760 d467b679 Gerd Hoffmann
    int isize;
761 d467b679 Gerd Hoffmann
762 d467b679 Gerd Hoffmann
    if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
763 d01f9595 Corentin Chary
        vnc_lock_output(vs);
764 d467b679 Gerd Hoffmann
        vnc_write_u8(vs,  VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
765 d467b679 Gerd Hoffmann
        vnc_write_u8(vs,  0);  /*  padding     */
766 d467b679 Gerd Hoffmann
        vnc_write_u16(vs, 1);  /*  # of rects  */
767 d467b679 Gerd Hoffmann
        vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
768 d467b679 Gerd Hoffmann
                               VNC_ENCODING_RICH_CURSOR);
769 d467b679 Gerd Hoffmann
        isize = c->width * c->height * vs->clientds.pf.bytes_per_pixel;
770 d467b679 Gerd Hoffmann
        vnc_write_pixels_generic(vs, &pf, c->data, isize);
771 d467b679 Gerd Hoffmann
        vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
772 d01f9595 Corentin Chary
        vnc_unlock_output(vs);
773 d467b679 Gerd Hoffmann
        return 0;
774 d467b679 Gerd Hoffmann
    }
775 d467b679 Gerd Hoffmann
    return -1;
776 d467b679 Gerd Hoffmann
}
777 d467b679 Gerd Hoffmann
778 d467b679 Gerd Hoffmann
static void vnc_dpy_cursor_define(QEMUCursor *c)
779 d467b679 Gerd Hoffmann
{
780 d467b679 Gerd Hoffmann
    VncDisplay *vd = vnc_display;
781 d467b679 Gerd Hoffmann
    VncState *vs;
782 d467b679 Gerd Hoffmann
783 d467b679 Gerd Hoffmann
    cursor_put(vd->cursor);
784 d467b679 Gerd Hoffmann
    qemu_free(vd->cursor_mask);
785 d467b679 Gerd Hoffmann
786 d467b679 Gerd Hoffmann
    vd->cursor = c;
787 d467b679 Gerd Hoffmann
    cursor_get(vd->cursor);
788 d467b679 Gerd Hoffmann
    vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
789 d467b679 Gerd Hoffmann
    vd->cursor_mask = qemu_mallocz(vd->cursor_msize);
790 d467b679 Gerd Hoffmann
    cursor_get_mono_mask(c, 0, vd->cursor_mask);
791 d467b679 Gerd Hoffmann
792 d467b679 Gerd Hoffmann
    QTAILQ_FOREACH(vs, &vd->clients, next) {
793 d467b679 Gerd Hoffmann
        vnc_cursor_define(vs);
794 d467b679 Gerd Hoffmann
    }
795 d467b679 Gerd Hoffmann
}
796 d467b679 Gerd Hoffmann
797 1fc62412 Stefano Stabellini
static int find_and_clear_dirty_height(struct VncState *vs,
798 6c71a539 Corentin Chary
                                       int y, int last_x, int x, int height)
799 24236869 bellard
{
800 24236869 bellard
    int h;
801 24236869 bellard
802 6c71a539 Corentin Chary
    for (h = 1; h < (height - y); h++) {
803 28a76be8 aliguori
        int tmp_x;
804 bc2429b9 Corentin Chary
        if (!test_bit(last_x, vs->dirty[y + h])) {
805 28a76be8 aliguori
            break;
806 bc2429b9 Corentin Chary
        }
807 bc2429b9 Corentin Chary
        for (tmp_x = last_x; tmp_x < x; tmp_x++) {
808 bc2429b9 Corentin Chary
            clear_bit(tmp_x, vs->dirty[y + h]);
809 bc2429b9 Corentin Chary
        }
810 24236869 bellard
    }
811 24236869 bellard
812 24236869 bellard
    return h;
813 24236869 bellard
}
814 24236869 bellard
815 bd023f95 Corentin Chary
#ifdef CONFIG_VNC_THREAD
816 bd023f95 Corentin Chary
static int vnc_update_client_sync(VncState *vs, int has_dirty)
817 bd023f95 Corentin Chary
{
818 bd023f95 Corentin Chary
    int ret = vnc_update_client(vs, has_dirty);
819 bd023f95 Corentin Chary
    vnc_jobs_join(vs);
820 bd023f95 Corentin Chary
    return ret;
821 bd023f95 Corentin Chary
}
822 bd023f95 Corentin Chary
#else
823 bd023f95 Corentin Chary
static int vnc_update_client_sync(VncState *vs, int has_dirty)
824 bd023f95 Corentin Chary
{
825 bd023f95 Corentin Chary
    return vnc_update_client(vs, has_dirty);
826 bd023f95 Corentin Chary
}
827 bd023f95 Corentin Chary
#endif
828 bd023f95 Corentin Chary
829 2430ffe4 Stefano Stabellini
static int vnc_update_client(VncState *vs, int has_dirty)
830 24236869 bellard
{
831 24236869 bellard
    if (vs->need_update && vs->csock != -1) {
832 1fc62412 Stefano Stabellini
        VncDisplay *vd = vs->vd;
833 bd023f95 Corentin Chary
        VncJob *job;
834 28a76be8 aliguori
        int y;
835 847ce6a1 Gerd Hoffmann
        int width, height;
836 bd023f95 Corentin Chary
        int n = 0;
837 bd023f95 Corentin Chary
838 24236869 bellard
839 703bc68f Stefano Stabellini
        if (vs->output.offset && !vs->audio_cap && !vs->force_update)
840 c522d0e2 aliguori
            /* kernel send buffers are full -> drop frames to throttle */
841 2430ffe4 Stefano Stabellini
            return 0;
842 a0ecfb73 balrog
843 703bc68f Stefano Stabellini
        if (!has_dirty && !vs->audio_cap && !vs->force_update)
844 2430ffe4 Stefano Stabellini
            return 0;
845 28a76be8 aliguori
846 6baebed7 aliguori
        /*
847 6baebed7 aliguori
         * Send screen updates to the vnc client using the server
848 6baebed7 aliguori
         * surface and server dirty map.  guest surface updates
849 6baebed7 aliguori
         * happening in parallel don't disturb us, the next pass will
850 6baebed7 aliguori
         * send them to the client.
851 6baebed7 aliguori
         */
852 bd023f95 Corentin Chary
        job = vnc_job_new(vs);
853 28a76be8 aliguori
854 847ce6a1 Gerd Hoffmann
        width = MIN(vd->server->width, vs->client_width);
855 847ce6a1 Gerd Hoffmann
        height = MIN(vd->server->height, vs->client_height);
856 847ce6a1 Gerd Hoffmann
857 847ce6a1 Gerd Hoffmann
        for (y = 0; y < height; y++) {
858 28a76be8 aliguori
            int x;
859 28a76be8 aliguori
            int last_x = -1;
860 847ce6a1 Gerd Hoffmann
            for (x = 0; x < width / 16; x++) {
861 bc2429b9 Corentin Chary
                if (test_and_clear_bit(x, vs->dirty[y])) {
862 28a76be8 aliguori
                    if (last_x == -1) {
863 28a76be8 aliguori
                        last_x = x;
864 28a76be8 aliguori
                    }
865 28a76be8 aliguori
                } else {
866 28a76be8 aliguori
                    if (last_x != -1) {
867 6c71a539 Corentin Chary
                        int h = find_and_clear_dirty_height(vs, y, last_x, x,
868 6c71a539 Corentin Chary
                                                            height);
869 bd023f95 Corentin Chary
870 bd023f95 Corentin Chary
                        n += vnc_job_add_rect(job, last_x * 16, y,
871 bd023f95 Corentin Chary
                                              (x - last_x) * 16, h);
872 28a76be8 aliguori
                    }
873 28a76be8 aliguori
                    last_x = -1;
874 28a76be8 aliguori
                }
875 28a76be8 aliguori
            }
876 28a76be8 aliguori
            if (last_x != -1) {
877 6c71a539 Corentin Chary
                int h = find_and_clear_dirty_height(vs, y, last_x, x, height);
878 bd023f95 Corentin Chary
                n += vnc_job_add_rect(job, last_x * 16, y,
879 bd023f95 Corentin Chary
                                      (x - last_x) * 16, h);
880 28a76be8 aliguori
            }
881 28a76be8 aliguori
        }
882 bd023f95 Corentin Chary
883 bd023f95 Corentin Chary
        vnc_job_push(job);
884 c522d0e2 aliguori
        vs->force_update = 0;
885 bd023f95 Corentin Chary
        return n;
886 24236869 bellard
    }
887 24236869 bellard
888 703bc68f Stefano Stabellini
    if (vs->csock == -1)
889 198a0039 Gerd Hoffmann
        vnc_disconnect_finish(vs);
890 2430ffe4 Stefano Stabellini
891 2430ffe4 Stefano Stabellini
    return 0;
892 24236869 bellard
}
893 24236869 bellard
894 429a8ed3 malc
/* audio */
895 429a8ed3 malc
static void audio_capture_notify(void *opaque, audcnotification_e cmd)
896 429a8ed3 malc
{
897 429a8ed3 malc
    VncState *vs = opaque;
898 429a8ed3 malc
899 429a8ed3 malc
    switch (cmd) {
900 429a8ed3 malc
    case AUD_CNOTIFY_DISABLE:
901 bd023f95 Corentin Chary
        vnc_lock_output(vs);
902 46a183da Daniel P. Berrange
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
903 46a183da Daniel P. Berrange
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
904 46a183da Daniel P. Berrange
        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
905 bd023f95 Corentin Chary
        vnc_unlock_output(vs);
906 429a8ed3 malc
        vnc_flush(vs);
907 429a8ed3 malc
        break;
908 429a8ed3 malc
909 429a8ed3 malc
    case AUD_CNOTIFY_ENABLE:
910 bd023f95 Corentin Chary
        vnc_lock_output(vs);
911 46a183da Daniel P. Berrange
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
912 46a183da Daniel P. Berrange
        vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
913 46a183da Daniel P. Berrange
        vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
914 bd023f95 Corentin Chary
        vnc_unlock_output(vs);
915 429a8ed3 malc
        vnc_flush(vs);
916 429a8ed3 malc
        break;
917 429a8ed3 malc
    }
918 429a8ed3 malc
}
919 429a8ed3 malc
920 429a8ed3 malc
static void audio_capture_destroy(void *opaque)
921 429a8ed3 malc
{
922 429a8ed3 malc
}
923 429a8ed3 malc
924 429a8ed3 malc
static void audio_capture(void *opaque, void *buf, int size)
925 429a8ed3 malc
{
926 429a8ed3 malc
    VncState *vs = opaque;
927 429a8ed3 malc
928 bd023f95 Corentin Chary
    vnc_lock_output(vs);
929 46a183da Daniel P. Berrange
    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
930 46a183da Daniel P. Berrange
    vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
931 46a183da Daniel P. Berrange
    vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
932 429a8ed3 malc
    vnc_write_u32(vs, size);
933 429a8ed3 malc
    vnc_write(vs, buf, size);
934 bd023f95 Corentin Chary
    vnc_unlock_output(vs);
935 429a8ed3 malc
    vnc_flush(vs);
936 429a8ed3 malc
}
937 429a8ed3 malc
938 429a8ed3 malc
static void audio_add(VncState *vs)
939 429a8ed3 malc
{
940 429a8ed3 malc
    struct audio_capture_ops ops;
941 429a8ed3 malc
942 429a8ed3 malc
    if (vs->audio_cap) {
943 8631b608 Markus Armbruster
        monitor_printf(default_mon, "audio already running\n");
944 429a8ed3 malc
        return;
945 429a8ed3 malc
    }
946 429a8ed3 malc
947 429a8ed3 malc
    ops.notify = audio_capture_notify;
948 429a8ed3 malc
    ops.destroy = audio_capture_destroy;
949 429a8ed3 malc
    ops.capture = audio_capture;
950 429a8ed3 malc
951 1a7dafce malc
    vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs);
952 429a8ed3 malc
    if (!vs->audio_cap) {
953 8631b608 Markus Armbruster
        monitor_printf(default_mon, "Failed to add audio capture\n");
954 429a8ed3 malc
    }
955 429a8ed3 malc
}
956 429a8ed3 malc
957 429a8ed3 malc
static void audio_del(VncState *vs)
958 429a8ed3 malc
{
959 429a8ed3 malc
    if (vs->audio_cap) {
960 429a8ed3 malc
        AUD_del_capture(vs->audio_cap, vs);
961 429a8ed3 malc
        vs->audio_cap = NULL;
962 429a8ed3 malc
    }
963 429a8ed3 malc
}
964 429a8ed3 malc
965 198a0039 Gerd Hoffmann
static void vnc_disconnect_start(VncState *vs)
966 198a0039 Gerd Hoffmann
{
967 198a0039 Gerd Hoffmann
    if (vs->csock == -1)
968 198a0039 Gerd Hoffmann
        return;
969 198a0039 Gerd Hoffmann
    qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
970 198a0039 Gerd Hoffmann
    closesocket(vs->csock);
971 198a0039 Gerd Hoffmann
    vs->csock = -1;
972 198a0039 Gerd Hoffmann
}
973 198a0039 Gerd Hoffmann
974 198a0039 Gerd Hoffmann
static void vnc_disconnect_finish(VncState *vs)
975 198a0039 Gerd Hoffmann
{
976 7d964c9d Corentin Chary
    int i;
977 7d964c9d Corentin Chary
978 bd023f95 Corentin Chary
    vnc_jobs_join(vs); /* Wait encoding jobs */
979 bd023f95 Corentin Chary
980 bd023f95 Corentin Chary
    vnc_lock_output(vs);
981 0d72f3d3 Luiz Capitulino
    vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED);
982 0d72f3d3 Luiz Capitulino
983 5d418e3b Corentin Chary
    buffer_free(&vs->input);
984 5d418e3b Corentin Chary
    buffer_free(&vs->output);
985 4a80dba3 Luiz Capitulino
986 4a80dba3 Luiz Capitulino
    qobject_decref(vs->info);
987 4a80dba3 Luiz Capitulino
988 161c4f20 Corentin Chary
    vnc_zlib_clear(vs);
989 380282b0 Corentin Chary
    vnc_tight_clear(vs);
990 148954fa Corentin Chary
    vnc_zrle_clear(vs);
991 161c4f20 Corentin Chary
992 198a0039 Gerd Hoffmann
#ifdef CONFIG_VNC_TLS
993 198a0039 Gerd Hoffmann
    vnc_tls_client_cleanup(vs);
994 198a0039 Gerd Hoffmann
#endif /* CONFIG_VNC_TLS */
995 198a0039 Gerd Hoffmann
#ifdef CONFIG_VNC_SASL
996 198a0039 Gerd Hoffmann
    vnc_sasl_client_cleanup(vs);
997 198a0039 Gerd Hoffmann
#endif /* CONFIG_VNC_SASL */
998 198a0039 Gerd Hoffmann
    audio_del(vs);
999 198a0039 Gerd Hoffmann
1000 41b4bef6 Amit Shah
    QTAILQ_REMOVE(&vs->vd->clients, vs, next);
1001 41b4bef6 Amit Shah
1002 41b4bef6 Amit Shah
    if (QTAILQ_EMPTY(&vs->vd->clients)) {
1003 198a0039 Gerd Hoffmann
        dcl->idle = 1;
1004 41b4bef6 Amit Shah
    }
1005 198a0039 Gerd Hoffmann
1006 37c34d9d Anthony Liguori
    qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
1007 703bc68f Stefano Stabellini
    vnc_remove_timer(vs->vd);
1008 3a0558b5 Gerd Hoffmann
    if (vs->vd->lock_key_sync)
1009 3a0558b5 Gerd Hoffmann
        qemu_remove_led_event_handler(vs->led);
1010 bd023f95 Corentin Chary
    vnc_unlock_output(vs);
1011 bd023f95 Corentin Chary
1012 bd023f95 Corentin Chary
#ifdef CONFIG_VNC_THREAD
1013 bd023f95 Corentin Chary
    qemu_mutex_destroy(&vs->output_mutex);
1014 bd023f95 Corentin Chary
#endif
1015 7d964c9d Corentin Chary
    for (i = 0; i < VNC_STAT_ROWS; ++i) {
1016 7d964c9d Corentin Chary
        qemu_free(vs->lossy_rect[i]);
1017 7d964c9d Corentin Chary
    }
1018 7d964c9d Corentin Chary
    qemu_free(vs->lossy_rect);
1019 5d95ac5b Glauber Costa
    qemu_free(vs);
1020 198a0039 Gerd Hoffmann
}
1021 2f9606b3 aliguori
1022 2f9606b3 aliguori
int vnc_client_io_error(VncState *vs, int ret, int last_errno)
1023 24236869 bellard
{
1024 24236869 bellard
    if (ret == 0 || ret == -1) {
1025 ea01e5fd balrog
        if (ret == -1) {
1026 ea01e5fd balrog
            switch (last_errno) {
1027 ea01e5fd balrog
                case EINTR:
1028 ea01e5fd balrog
                case EAGAIN:
1029 ea01e5fd balrog
#ifdef _WIN32
1030 ea01e5fd balrog
                case WSAEWOULDBLOCK:
1031 ea01e5fd balrog
#endif
1032 ea01e5fd balrog
                    return 0;
1033 ea01e5fd balrog
                default:
1034 ea01e5fd balrog
                    break;
1035 ea01e5fd balrog
            }
1036 ea01e5fd balrog
        }
1037 24236869 bellard
1038 198a0039 Gerd Hoffmann
        VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
1039 198a0039 Gerd Hoffmann
                  ret, ret < 0 ? last_errno : 0);
1040 198a0039 Gerd Hoffmann
        vnc_disconnect_start(vs);
1041 6baebed7 aliguori
1042 28a76be8 aliguori
        return 0;
1043 24236869 bellard
    }
1044 24236869 bellard
    return ret;
1045 24236869 bellard
}
1046 24236869 bellard
1047 5fb6c7a8 aliguori
1048 5fb6c7a8 aliguori
void vnc_client_error(VncState *vs)
1049 24236869 bellard
{
1050 198a0039 Gerd Hoffmann
    VNC_DEBUG("Closing down client sock: protocol error\n");
1051 198a0039 Gerd Hoffmann
    vnc_disconnect_start(vs);
1052 24236869 bellard
}
1053 24236869 bellard
1054 2f9606b3 aliguori
1055 2f9606b3 aliguori
/*
1056 2f9606b3 aliguori
 * Called to write a chunk of data to the client socket. The data may
1057 2f9606b3 aliguori
 * be the raw data, or may have already been encoded by SASL.
1058 2f9606b3 aliguori
 * The data will be written either straight onto the socket, or
1059 2f9606b3 aliguori
 * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1060 2f9606b3 aliguori
 *
1061 2f9606b3 aliguori
 * NB, it is theoretically possible to have 2 layers of encryption,
1062 2f9606b3 aliguori
 * both SASL, and this TLS layer. It is highly unlikely in practice
1063 2f9606b3 aliguori
 * though, since SASL encryption will typically be a no-op if TLS
1064 2f9606b3 aliguori
 * is active
1065 2f9606b3 aliguori
 *
1066 2f9606b3 aliguori
 * Returns the number of bytes written, which may be less than
1067 2f9606b3 aliguori
 * the requested 'datalen' if the socket would block. Returns
1068 2f9606b3 aliguori
 * -1 on error, and disconnects the client socket.
1069 2f9606b3 aliguori
 */
1070 2f9606b3 aliguori
long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
1071 24236869 bellard
{
1072 ceb5caaf bellard
    long ret;
1073 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
1074 5fb6c7a8 aliguori
    if (vs->tls.session) {
1075 28a76be8 aliguori
        ret = gnutls_write(vs->tls.session, data, datalen);
1076 28a76be8 aliguori
        if (ret < 0) {
1077 28a76be8 aliguori
            if (ret == GNUTLS_E_AGAIN)
1078 28a76be8 aliguori
                errno = EAGAIN;
1079 28a76be8 aliguori
            else
1080 28a76be8 aliguori
                errno = EIO;
1081 28a76be8 aliguori
            ret = -1;
1082 28a76be8 aliguori
        }
1083 8d5d2d4c ths
    } else
1084 8d5d2d4c ths
#endif /* CONFIG_VNC_TLS */
1085 70503264 Stefan Weil
        ret = send(vs->csock, (const void *)data, datalen, 0);
1086 23decc87 aliguori
    VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
1087 2f9606b3 aliguori
    return vnc_client_io_error(vs, ret, socket_error());
1088 2f9606b3 aliguori
}
1089 2f9606b3 aliguori
1090 2f9606b3 aliguori
1091 2f9606b3 aliguori
/*
1092 2f9606b3 aliguori
 * Called to write buffered data to the client socket, when not
1093 2f9606b3 aliguori
 * using any SASL SSF encryption layers. Will write as much data
1094 2f9606b3 aliguori
 * as possible without blocking. If all buffered data is written,
1095 2f9606b3 aliguori
 * will switch the FD poll() handler back to read monitoring.
1096 2f9606b3 aliguori
 *
1097 2f9606b3 aliguori
 * Returns the number of bytes written, which may be less than
1098 2f9606b3 aliguori
 * the buffered output data if the socket would block. Returns
1099 2f9606b3 aliguori
 * -1 on error, and disconnects the client socket.
1100 2f9606b3 aliguori
 */
1101 2f9606b3 aliguori
static long vnc_client_write_plain(VncState *vs)
1102 2f9606b3 aliguori
{
1103 2f9606b3 aliguori
    long ret;
1104 2f9606b3 aliguori
1105 2f9606b3 aliguori
#ifdef CONFIG_VNC_SASL
1106 23decc87 aliguori
    VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
1107 2f9606b3 aliguori
              vs->output.buffer, vs->output.capacity, vs->output.offset,
1108 2f9606b3 aliguori
              vs->sasl.waitWriteSSF);
1109 2f9606b3 aliguori
1110 2f9606b3 aliguori
    if (vs->sasl.conn &&
1111 2f9606b3 aliguori
        vs->sasl.runSSF &&
1112 2f9606b3 aliguori
        vs->sasl.waitWriteSSF) {
1113 2f9606b3 aliguori
        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF);
1114 2f9606b3 aliguori
        if (ret)
1115 2f9606b3 aliguori
            vs->sasl.waitWriteSSF -= ret;
1116 2f9606b3 aliguori
    } else
1117 2f9606b3 aliguori
#endif /* CONFIG_VNC_SASL */
1118 2f9606b3 aliguori
        ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset);
1119 24236869 bellard
    if (!ret)
1120 2f9606b3 aliguori
        return 0;
1121 24236869 bellard
1122 24236869 bellard
    memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret));
1123 24236869 bellard
    vs->output.offset -= ret;
1124 24236869 bellard
1125 24236869 bellard
    if (vs->output.offset == 0) {
1126 28a76be8 aliguori
        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
1127 24236869 bellard
    }
1128 2f9606b3 aliguori
1129 2f9606b3 aliguori
    return ret;
1130 2f9606b3 aliguori
}
1131 2f9606b3 aliguori
1132 2f9606b3 aliguori
1133 2f9606b3 aliguori
/*
1134 2f9606b3 aliguori
 * First function called whenever there is data to be written to
1135 2f9606b3 aliguori
 * the client socket. Will delegate actual work according to whether
1136 2f9606b3 aliguori
 * SASL SSF layers are enabled (thus requiring encryption calls)
1137 2f9606b3 aliguori
 */
1138 bd023f95 Corentin Chary
static void vnc_client_write_locked(void *opaque)
1139 2f9606b3 aliguori
{
1140 2f9606b3 aliguori
    VncState *vs = opaque;
1141 2f9606b3 aliguori
1142 2f9606b3 aliguori
#ifdef CONFIG_VNC_SASL
1143 2f9606b3 aliguori
    if (vs->sasl.conn &&
1144 2f9606b3 aliguori
        vs->sasl.runSSF &&
1145 9678d950 Blue Swirl
        !vs->sasl.waitWriteSSF) {
1146 9678d950 Blue Swirl
        vnc_client_write_sasl(vs);
1147 9678d950 Blue Swirl
    } else
1148 2f9606b3 aliguori
#endif /* CONFIG_VNC_SASL */
1149 9678d950 Blue Swirl
        vnc_client_write_plain(vs);
1150 24236869 bellard
}
1151 24236869 bellard
1152 bd023f95 Corentin Chary
void vnc_client_write(void *opaque)
1153 bd023f95 Corentin Chary
{
1154 bd023f95 Corentin Chary
    VncState *vs = opaque;
1155 bd023f95 Corentin Chary
1156 bd023f95 Corentin Chary
    vnc_lock_output(vs);
1157 bd023f95 Corentin Chary
    if (vs->output.offset) {
1158 bd023f95 Corentin Chary
        vnc_client_write_locked(opaque);
1159 ac71103d Yoshiaki Tamura
    } else if (vs->csock != -1) {
1160 bd023f95 Corentin Chary
        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
1161 bd023f95 Corentin Chary
    }
1162 bd023f95 Corentin Chary
    vnc_unlock_output(vs);
1163 bd023f95 Corentin Chary
}
1164 bd023f95 Corentin Chary
1165 5fb6c7a8 aliguori
void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
1166 24236869 bellard
{
1167 24236869 bellard
    vs->read_handler = func;
1168 24236869 bellard
    vs->read_handler_expect = expecting;
1169 24236869 bellard
}
1170 24236869 bellard
1171 2f9606b3 aliguori
1172 2f9606b3 aliguori
/*
1173 2f9606b3 aliguori
 * Called to read a chunk of data from the client socket. The data may
1174 2f9606b3 aliguori
 * be the raw data, or may need to be further decoded by SASL.
1175 2f9606b3 aliguori
 * The data will be read either straight from to the socket, or
1176 2f9606b3 aliguori
 * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled
1177 2f9606b3 aliguori
 *
1178 2f9606b3 aliguori
 * NB, it is theoretically possible to have 2 layers of encryption,
1179 2f9606b3 aliguori
 * both SASL, and this TLS layer. It is highly unlikely in practice
1180 2f9606b3 aliguori
 * though, since SASL encryption will typically be a no-op if TLS
1181 2f9606b3 aliguori
 * is active
1182 2f9606b3 aliguori
 *
1183 2f9606b3 aliguori
 * Returns the number of bytes read, which may be less than
1184 2f9606b3 aliguori
 * the requested 'datalen' if the socket would block. Returns
1185 2f9606b3 aliguori
 * -1 on error, and disconnects the client socket.
1186 2f9606b3 aliguori
 */
1187 2f9606b3 aliguori
long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
1188 24236869 bellard
{
1189 ceb5caaf bellard
    long ret;
1190 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
1191 5fb6c7a8 aliguori
    if (vs->tls.session) {
1192 28a76be8 aliguori
        ret = gnutls_read(vs->tls.session, data, datalen);
1193 28a76be8 aliguori
        if (ret < 0) {
1194 28a76be8 aliguori
            if (ret == GNUTLS_E_AGAIN)
1195 28a76be8 aliguori
                errno = EAGAIN;
1196 28a76be8 aliguori
            else
1197 28a76be8 aliguori
                errno = EIO;
1198 28a76be8 aliguori
            ret = -1;
1199 28a76be8 aliguori
        }
1200 8d5d2d4c ths
    } else
1201 8d5d2d4c ths
#endif /* CONFIG_VNC_TLS */
1202 c5b76b38 Blue Swirl
        ret = recv(vs->csock, (void *)data, datalen, 0);
1203 23decc87 aliguori
    VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
1204 2f9606b3 aliguori
    return vnc_client_io_error(vs, ret, socket_error());
1205 2f9606b3 aliguori
}
1206 24236869 bellard
1207 2f9606b3 aliguori
1208 2f9606b3 aliguori
/*
1209 2f9606b3 aliguori
 * Called to read data from the client socket to the input buffer,
1210 2f9606b3 aliguori
 * when not using any SASL SSF encryption layers. Will read as much
1211 2f9606b3 aliguori
 * data as possible without blocking.
1212 2f9606b3 aliguori
 *
1213 2f9606b3 aliguori
 * Returns the number of bytes read. Returns -1 on error, and
1214 2f9606b3 aliguori
 * disconnects the client socket.
1215 2f9606b3 aliguori
 */
1216 2f9606b3 aliguori
static long vnc_client_read_plain(VncState *vs)
1217 2f9606b3 aliguori
{
1218 2f9606b3 aliguori
    int ret;
1219 23decc87 aliguori
    VNC_DEBUG("Read plain %p size %zd offset %zd\n",
1220 2f9606b3 aliguori
              vs->input.buffer, vs->input.capacity, vs->input.offset);
1221 2f9606b3 aliguori
    buffer_reserve(&vs->input, 4096);
1222 2f9606b3 aliguori
    ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
1223 2f9606b3 aliguori
    if (!ret)
1224 2f9606b3 aliguori
        return 0;
1225 24236869 bellard
    vs->input.offset += ret;
1226 2f9606b3 aliguori
    return ret;
1227 2f9606b3 aliguori
}
1228 2f9606b3 aliguori
1229 2f9606b3 aliguori
1230 2f9606b3 aliguori
/*
1231 2f9606b3 aliguori
 * First function called whenever there is more data to be read from
1232 2f9606b3 aliguori
 * the client socket. Will delegate actual work according to whether
1233 2f9606b3 aliguori
 * SASL SSF layers are enabled (thus requiring decryption calls)
1234 2f9606b3 aliguori
 */
1235 2f9606b3 aliguori
void vnc_client_read(void *opaque)
1236 2f9606b3 aliguori
{
1237 2f9606b3 aliguori
    VncState *vs = opaque;
1238 2f9606b3 aliguori
    long ret;
1239 2f9606b3 aliguori
1240 2f9606b3 aliguori
#ifdef CONFIG_VNC_SASL
1241 2f9606b3 aliguori
    if (vs->sasl.conn && vs->sasl.runSSF)
1242 2f9606b3 aliguori
        ret = vnc_client_read_sasl(vs);
1243 2f9606b3 aliguori
    else
1244 2f9606b3 aliguori
#endif /* CONFIG_VNC_SASL */
1245 2f9606b3 aliguori
        ret = vnc_client_read_plain(vs);
1246 198a0039 Gerd Hoffmann
    if (!ret) {
1247 198a0039 Gerd Hoffmann
        if (vs->csock == -1)
1248 198a0039 Gerd Hoffmann
            vnc_disconnect_finish(vs);
1249 28a76be8 aliguori
        return;
1250 198a0039 Gerd Hoffmann
    }
1251 24236869 bellard
1252 24236869 bellard
    while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
1253 28a76be8 aliguori
        size_t len = vs->read_handler_expect;
1254 28a76be8 aliguori
        int ret;
1255 28a76be8 aliguori
1256 28a76be8 aliguori
        ret = vs->read_handler(vs, vs->input.buffer, len);
1257 198a0039 Gerd Hoffmann
        if (vs->csock == -1) {
1258 198a0039 Gerd Hoffmann
            vnc_disconnect_finish(vs);
1259 28a76be8 aliguori
            return;
1260 198a0039 Gerd Hoffmann
        }
1261 28a76be8 aliguori
1262 28a76be8 aliguori
        if (!ret) {
1263 28a76be8 aliguori
            memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len));
1264 28a76be8 aliguori
            vs->input.offset -= len;
1265 28a76be8 aliguori
        } else {
1266 28a76be8 aliguori
            vs->read_handler_expect = ret;
1267 28a76be8 aliguori
        }
1268 24236869 bellard
    }
1269 24236869 bellard
}
1270 24236869 bellard
1271 5fb6c7a8 aliguori
void vnc_write(VncState *vs, const void *data, size_t len)
1272 24236869 bellard
{
1273 24236869 bellard
    buffer_reserve(&vs->output, len);
1274 24236869 bellard
1275 198a0039 Gerd Hoffmann
    if (vs->csock != -1 && buffer_empty(&vs->output)) {
1276 28a76be8 aliguori
        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
1277 24236869 bellard
    }
1278 24236869 bellard
1279 24236869 bellard
    buffer_append(&vs->output, data, len);
1280 24236869 bellard
}
1281 24236869 bellard
1282 5fb6c7a8 aliguori
void vnc_write_s32(VncState *vs, int32_t value)
1283 24236869 bellard
{
1284 24236869 bellard
    vnc_write_u32(vs, *(uint32_t *)&value);
1285 24236869 bellard
}
1286 24236869 bellard
1287 5fb6c7a8 aliguori
void vnc_write_u32(VncState *vs, uint32_t value)
1288 24236869 bellard
{
1289 24236869 bellard
    uint8_t buf[4];
1290 24236869 bellard
1291 24236869 bellard
    buf[0] = (value >> 24) & 0xFF;
1292 24236869 bellard
    buf[1] = (value >> 16) & 0xFF;
1293 24236869 bellard
    buf[2] = (value >>  8) & 0xFF;
1294 24236869 bellard
    buf[3] = value & 0xFF;
1295 24236869 bellard
1296 24236869 bellard
    vnc_write(vs, buf, 4);
1297 24236869 bellard
}
1298 24236869 bellard
1299 5fb6c7a8 aliguori
void vnc_write_u16(VncState *vs, uint16_t value)
1300 24236869 bellard
{
1301 64f5a135 bellard
    uint8_t buf[2];
1302 24236869 bellard
1303 24236869 bellard
    buf[0] = (value >> 8) & 0xFF;
1304 24236869 bellard
    buf[1] = value & 0xFF;
1305 24236869 bellard
1306 24236869 bellard
    vnc_write(vs, buf, 2);
1307 24236869 bellard
}
1308 24236869 bellard
1309 5fb6c7a8 aliguori
void vnc_write_u8(VncState *vs, uint8_t value)
1310 24236869 bellard
{
1311 24236869 bellard
    vnc_write(vs, (char *)&value, 1);
1312 24236869 bellard
}
1313 24236869 bellard
1314 5fb6c7a8 aliguori
void vnc_flush(VncState *vs)
1315 24236869 bellard
{
1316 bd023f95 Corentin Chary
    vnc_lock_output(vs);
1317 bd023f95 Corentin Chary
    if (vs->csock != -1 && vs->output.offset) {
1318 bd023f95 Corentin Chary
        vnc_client_write_locked(vs);
1319 bd023f95 Corentin Chary
    }
1320 bd023f95 Corentin Chary
    vnc_unlock_output(vs);
1321 24236869 bellard
}
1322 24236869 bellard
1323 5fb6c7a8 aliguori
uint8_t read_u8(uint8_t *data, size_t offset)
1324 24236869 bellard
{
1325 24236869 bellard
    return data[offset];
1326 24236869 bellard
}
1327 24236869 bellard
1328 5fb6c7a8 aliguori
uint16_t read_u16(uint8_t *data, size_t offset)
1329 24236869 bellard
{
1330 24236869 bellard
    return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
1331 24236869 bellard
}
1332 24236869 bellard
1333 5fb6c7a8 aliguori
int32_t read_s32(uint8_t *data, size_t offset)
1334 24236869 bellard
{
1335 24236869 bellard
    return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
1336 28a76be8 aliguori
                     (data[offset + 2] << 8) | data[offset + 3]);
1337 24236869 bellard
}
1338 24236869 bellard
1339 5fb6c7a8 aliguori
uint32_t read_u32(uint8_t *data, size_t offset)
1340 24236869 bellard
{
1341 24236869 bellard
    return ((data[offset] << 24) | (data[offset + 1] << 16) |
1342 28a76be8 aliguori
            (data[offset + 2] << 8) | data[offset + 3]);
1343 24236869 bellard
}
1344 24236869 bellard
1345 60fe76f3 ths
static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
1346 24236869 bellard
{
1347 24236869 bellard
}
1348 24236869 bellard
1349 37c34d9d Anthony Liguori
static void check_pointer_type_change(Notifier *notifier)
1350 564c337e bellard
{
1351 37c34d9d Anthony Liguori
    VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
1352 37c34d9d Anthony Liguori
    int absolute = kbd_mouse_is_absolute();
1353 37c34d9d Anthony Liguori
1354 29fa4ed9 aliguori
    if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
1355 bd023f95 Corentin Chary
        vnc_lock_output(vs);
1356 46a183da Daniel P. Berrange
        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1357 28a76be8 aliguori
        vnc_write_u8(vs, 0);
1358 28a76be8 aliguori
        vnc_write_u16(vs, 1);
1359 28a76be8 aliguori
        vnc_framebuffer_update(vs, absolute, 0,
1360 28a76be8 aliguori
                               ds_get_width(vs->ds), ds_get_height(vs->ds),
1361 29fa4ed9 aliguori
                               VNC_ENCODING_POINTER_TYPE_CHANGE);
1362 bd023f95 Corentin Chary
        vnc_unlock_output(vs);
1363 28a76be8 aliguori
        vnc_flush(vs);
1364 564c337e bellard
    }
1365 564c337e bellard
    vs->absolute = absolute;
1366 564c337e bellard
}
1367 564c337e bellard
1368 24236869 bellard
static void pointer_event(VncState *vs, int button_mask, int x, int y)
1369 24236869 bellard
{
1370 24236869 bellard
    int buttons = 0;
1371 24236869 bellard
    int dz = 0;
1372 24236869 bellard
1373 24236869 bellard
    if (button_mask & 0x01)
1374 28a76be8 aliguori
        buttons |= MOUSE_EVENT_LBUTTON;
1375 24236869 bellard
    if (button_mask & 0x02)
1376 28a76be8 aliguori
        buttons |= MOUSE_EVENT_MBUTTON;
1377 24236869 bellard
    if (button_mask & 0x04)
1378 28a76be8 aliguori
        buttons |= MOUSE_EVENT_RBUTTON;
1379 24236869 bellard
    if (button_mask & 0x08)
1380 28a76be8 aliguori
        dz = -1;
1381 24236869 bellard
    if (button_mask & 0x10)
1382 28a76be8 aliguori
        dz = 1;
1383 564c337e bellard
1384 564c337e bellard
    if (vs->absolute) {
1385 cc39a92c Chris Webb
        kbd_mouse_event(ds_get_width(vs->ds) > 1 ?
1386 cc39a92c Chris Webb
                          x * 0x7FFF / (ds_get_width(vs->ds) - 1) : 0x4000,
1387 cc39a92c Chris Webb
                        ds_get_height(vs->ds) > 1 ?
1388 cc39a92c Chris Webb
                          y * 0x7FFF / (ds_get_height(vs->ds) - 1) : 0x4000,
1389 28a76be8 aliguori
                        dz, buttons);
1390 29fa4ed9 aliguori
    } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
1391 28a76be8 aliguori
        x -= 0x7FFF;
1392 28a76be8 aliguori
        y -= 0x7FFF;
1393 24236869 bellard
1394 28a76be8 aliguori
        kbd_mouse_event(x, y, dz, buttons);
1395 564c337e bellard
    } else {
1396 28a76be8 aliguori
        if (vs->last_x != -1)
1397 28a76be8 aliguori
            kbd_mouse_event(x - vs->last_x,
1398 28a76be8 aliguori
                            y - vs->last_y,
1399 28a76be8 aliguori
                            dz, buttons);
1400 28a76be8 aliguori
        vs->last_x = x;
1401 28a76be8 aliguori
        vs->last_y = y;
1402 24236869 bellard
    }
1403 24236869 bellard
}
1404 24236869 bellard
1405 64f5a135 bellard
static void reset_keys(VncState *vs)
1406 64f5a135 bellard
{
1407 64f5a135 bellard
    int i;
1408 64f5a135 bellard
    for(i = 0; i < 256; i++) {
1409 64f5a135 bellard
        if (vs->modifiers_state[i]) {
1410 44bb61c8 Samuel Thibault
            if (i & SCANCODE_GREY)
1411 44bb61c8 Samuel Thibault
                kbd_put_keycode(SCANCODE_EMUL0);
1412 44bb61c8 Samuel Thibault
            kbd_put_keycode(i | SCANCODE_UP);
1413 64f5a135 bellard
            vs->modifiers_state[i] = 0;
1414 64f5a135 bellard
        }
1415 64f5a135 bellard
    }
1416 64f5a135 bellard
}
1417 64f5a135 bellard
1418 a528b80c balrog
static void press_key(VncState *vs, int keysym)
1419 a528b80c balrog
{
1420 44bb61c8 Samuel Thibault
    int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
1421 44bb61c8 Samuel Thibault
    if (keycode & SCANCODE_GREY)
1422 44bb61c8 Samuel Thibault
        kbd_put_keycode(SCANCODE_EMUL0);
1423 44bb61c8 Samuel Thibault
    kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
1424 44bb61c8 Samuel Thibault
    if (keycode & SCANCODE_GREY)
1425 44bb61c8 Samuel Thibault
        kbd_put_keycode(SCANCODE_EMUL0);
1426 44bb61c8 Samuel Thibault
    kbd_put_keycode(keycode | SCANCODE_UP);
1427 a528b80c balrog
}
1428 a528b80c balrog
1429 7ffb82ca Gerd Hoffmann
static void kbd_leds(void *opaque, int ledstate)
1430 7ffb82ca Gerd Hoffmann
{
1431 7ffb82ca Gerd Hoffmann
    VncState *vs = opaque;
1432 7ffb82ca Gerd Hoffmann
    int caps, num;
1433 7ffb82ca Gerd Hoffmann
1434 7ffb82ca Gerd Hoffmann
    caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
1435 7ffb82ca Gerd Hoffmann
    num  = ledstate & QEMU_NUM_LOCK_LED  ? 1 : 0;
1436 7ffb82ca Gerd Hoffmann
1437 7ffb82ca Gerd Hoffmann
    if (vs->modifiers_state[0x3a] != caps) {
1438 7ffb82ca Gerd Hoffmann
        vs->modifiers_state[0x3a] = caps;
1439 7ffb82ca Gerd Hoffmann
    }
1440 7ffb82ca Gerd Hoffmann
    if (vs->modifiers_state[0x45] != num) {
1441 7ffb82ca Gerd Hoffmann
        vs->modifiers_state[0x45] = num;
1442 7ffb82ca Gerd Hoffmann
    }
1443 7ffb82ca Gerd Hoffmann
}
1444 7ffb82ca Gerd Hoffmann
1445 9ca313aa aliguori
static void do_key_event(VncState *vs, int down, int keycode, int sym)
1446 24236869 bellard
{
1447 64f5a135 bellard
    /* QEMU console switch */
1448 64f5a135 bellard
    switch(keycode) {
1449 64f5a135 bellard
    case 0x2a:                          /* Left Shift */
1450 64f5a135 bellard
    case 0x36:                          /* Right Shift */
1451 64f5a135 bellard
    case 0x1d:                          /* Left CTRL */
1452 64f5a135 bellard
    case 0x9d:                          /* Right CTRL */
1453 64f5a135 bellard
    case 0x38:                          /* Left ALT */
1454 64f5a135 bellard
    case 0xb8:                          /* Right ALT */
1455 64f5a135 bellard
        if (down)
1456 64f5a135 bellard
            vs->modifiers_state[keycode] = 1;
1457 64f5a135 bellard
        else
1458 64f5a135 bellard
            vs->modifiers_state[keycode] = 0;
1459 64f5a135 bellard
        break;
1460 5fafdf24 ths
    case 0x02 ... 0x0a: /* '1' to '9' keys */
1461 64f5a135 bellard
        if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
1462 64f5a135 bellard
            /* Reset the modifiers sent to the current console */
1463 64f5a135 bellard
            reset_keys(vs);
1464 64f5a135 bellard
            console_select(keycode - 0x02);
1465 64f5a135 bellard
            return;
1466 64f5a135 bellard
        }
1467 64f5a135 bellard
        break;
1468 28a76be8 aliguori
    case 0x3a:                        /* CapsLock */
1469 28a76be8 aliguori
    case 0x45:                        /* NumLock */
1470 7ffb82ca Gerd Hoffmann
        if (down)
1471 a528b80c balrog
            vs->modifiers_state[keycode] ^= 1;
1472 a528b80c balrog
        break;
1473 a528b80c balrog
    }
1474 a528b80c balrog
1475 9892088b Gerd Hoffmann
    if (down && vs->vd->lock_key_sync &&
1476 3a0558b5 Gerd Hoffmann
        keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
1477 a528b80c balrog
        /* If the numlock state needs to change then simulate an additional
1478 a528b80c balrog
           keypress before sending this one.  This will happen if the user
1479 a528b80c balrog
           toggles numlock away from the VNC window.
1480 a528b80c balrog
        */
1481 753b4053 aliguori
        if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
1482 a528b80c balrog
            if (!vs->modifiers_state[0x45]) {
1483 a528b80c balrog
                vs->modifiers_state[0x45] = 1;
1484 a528b80c balrog
                press_key(vs, 0xff7f);
1485 a528b80c balrog
            }
1486 a528b80c balrog
        } else {
1487 a528b80c balrog
            if (vs->modifiers_state[0x45]) {
1488 a528b80c balrog
                vs->modifiers_state[0x45] = 0;
1489 a528b80c balrog
                press_key(vs, 0xff7f);
1490 a528b80c balrog
            }
1491 a528b80c balrog
        }
1492 64f5a135 bellard
    }
1493 24236869 bellard
1494 9892088b Gerd Hoffmann
    if (down && vs->vd->lock_key_sync &&
1495 3a0558b5 Gerd Hoffmann
        ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) {
1496 6b132502 Gerd Hoffmann
        /* If the capslock state needs to change then simulate an additional
1497 6b132502 Gerd Hoffmann
           keypress before sending this one.  This will happen if the user
1498 6b132502 Gerd Hoffmann
           toggles capslock away from the VNC window.
1499 6b132502 Gerd Hoffmann
        */
1500 6b132502 Gerd Hoffmann
        int uppercase = !!(sym >= 'A' && sym <= 'Z');
1501 6b132502 Gerd Hoffmann
        int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]);
1502 6b132502 Gerd Hoffmann
        int capslock = !!(vs->modifiers_state[0x3a]);
1503 6b132502 Gerd Hoffmann
        if (capslock) {
1504 6b132502 Gerd Hoffmann
            if (uppercase == shift) {
1505 6b132502 Gerd Hoffmann
                vs->modifiers_state[0x3a] = 0;
1506 6b132502 Gerd Hoffmann
                press_key(vs, 0xffe5);
1507 6b132502 Gerd Hoffmann
            }
1508 6b132502 Gerd Hoffmann
        } else {
1509 6b132502 Gerd Hoffmann
            if (uppercase != shift) {
1510 6b132502 Gerd Hoffmann
                vs->modifiers_state[0x3a] = 1;
1511 6b132502 Gerd Hoffmann
                press_key(vs, 0xffe5);
1512 6b132502 Gerd Hoffmann
            }
1513 6b132502 Gerd Hoffmann
        }
1514 6b132502 Gerd Hoffmann
    }
1515 6b132502 Gerd Hoffmann
1516 64f5a135 bellard
    if (is_graphic_console()) {
1517 44bb61c8 Samuel Thibault
        if (keycode & SCANCODE_GREY)
1518 44bb61c8 Samuel Thibault
            kbd_put_keycode(SCANCODE_EMUL0);
1519 64f5a135 bellard
        if (down)
1520 44bb61c8 Samuel Thibault
            kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
1521 64f5a135 bellard
        else
1522 44bb61c8 Samuel Thibault
            kbd_put_keycode(keycode | SCANCODE_UP);
1523 64f5a135 bellard
    } else {
1524 64f5a135 bellard
        /* QEMU console emulation */
1525 64f5a135 bellard
        if (down) {
1526 bb0a18e1 Gerd Hoffmann
            int numlock = vs->modifiers_state[0x45];
1527 64f5a135 bellard
            switch (keycode) {
1528 64f5a135 bellard
            case 0x2a:                          /* Left Shift */
1529 64f5a135 bellard
            case 0x36:                          /* Right Shift */
1530 64f5a135 bellard
            case 0x1d:                          /* Left CTRL */
1531 64f5a135 bellard
            case 0x9d:                          /* Right CTRL */
1532 64f5a135 bellard
            case 0x38:                          /* Left ALT */
1533 64f5a135 bellard
            case 0xb8:                          /* Right ALT */
1534 64f5a135 bellard
                break;
1535 64f5a135 bellard
            case 0xc8:
1536 64f5a135 bellard
                kbd_put_keysym(QEMU_KEY_UP);
1537 64f5a135 bellard
                break;
1538 64f5a135 bellard
            case 0xd0:
1539 64f5a135 bellard
                kbd_put_keysym(QEMU_KEY_DOWN);
1540 64f5a135 bellard
                break;
1541 64f5a135 bellard
            case 0xcb:
1542 64f5a135 bellard
                kbd_put_keysym(QEMU_KEY_LEFT);
1543 64f5a135 bellard
                break;
1544 64f5a135 bellard
            case 0xcd:
1545 64f5a135 bellard
                kbd_put_keysym(QEMU_KEY_RIGHT);
1546 64f5a135 bellard
                break;
1547 64f5a135 bellard
            case 0xd3:
1548 64f5a135 bellard
                kbd_put_keysym(QEMU_KEY_DELETE);
1549 64f5a135 bellard
                break;
1550 64f5a135 bellard
            case 0xc7:
1551 64f5a135 bellard
                kbd_put_keysym(QEMU_KEY_HOME);
1552 64f5a135 bellard
                break;
1553 64f5a135 bellard
            case 0xcf:
1554 64f5a135 bellard
                kbd_put_keysym(QEMU_KEY_END);
1555 64f5a135 bellard
                break;
1556 64f5a135 bellard
            case 0xc9:
1557 64f5a135 bellard
                kbd_put_keysym(QEMU_KEY_PAGEUP);
1558 64f5a135 bellard
                break;
1559 64f5a135 bellard
            case 0xd1:
1560 64f5a135 bellard
                kbd_put_keysym(QEMU_KEY_PAGEDOWN);
1561 64f5a135 bellard
                break;
1562 bb0a18e1 Gerd Hoffmann
1563 bb0a18e1 Gerd Hoffmann
            case 0x47:
1564 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME);
1565 bb0a18e1 Gerd Hoffmann
                break;
1566 bb0a18e1 Gerd Hoffmann
            case 0x48:
1567 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP);
1568 bb0a18e1 Gerd Hoffmann
                break;
1569 bb0a18e1 Gerd Hoffmann
            case 0x49:
1570 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP);
1571 bb0a18e1 Gerd Hoffmann
                break;
1572 bb0a18e1 Gerd Hoffmann
            case 0x4b:
1573 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT);
1574 bb0a18e1 Gerd Hoffmann
                break;
1575 bb0a18e1 Gerd Hoffmann
            case 0x4c:
1576 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym('5');
1577 bb0a18e1 Gerd Hoffmann
                break;
1578 bb0a18e1 Gerd Hoffmann
            case 0x4d:
1579 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT);
1580 bb0a18e1 Gerd Hoffmann
                break;
1581 bb0a18e1 Gerd Hoffmann
            case 0x4f:
1582 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym(numlock ? '1' : QEMU_KEY_END);
1583 bb0a18e1 Gerd Hoffmann
                break;
1584 bb0a18e1 Gerd Hoffmann
            case 0x50:
1585 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN);
1586 bb0a18e1 Gerd Hoffmann
                break;
1587 bb0a18e1 Gerd Hoffmann
            case 0x51:
1588 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN);
1589 bb0a18e1 Gerd Hoffmann
                break;
1590 bb0a18e1 Gerd Hoffmann
            case 0x52:
1591 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym('0');
1592 bb0a18e1 Gerd Hoffmann
                break;
1593 bb0a18e1 Gerd Hoffmann
            case 0x53:
1594 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE);
1595 bb0a18e1 Gerd Hoffmann
                break;
1596 bb0a18e1 Gerd Hoffmann
1597 bb0a18e1 Gerd Hoffmann
            case 0xb5:
1598 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym('/');
1599 bb0a18e1 Gerd Hoffmann
                break;
1600 bb0a18e1 Gerd Hoffmann
            case 0x37:
1601 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym('*');
1602 bb0a18e1 Gerd Hoffmann
                break;
1603 bb0a18e1 Gerd Hoffmann
            case 0x4a:
1604 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym('-');
1605 bb0a18e1 Gerd Hoffmann
                break;
1606 bb0a18e1 Gerd Hoffmann
            case 0x4e:
1607 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym('+');
1608 bb0a18e1 Gerd Hoffmann
                break;
1609 bb0a18e1 Gerd Hoffmann
            case 0x9c:
1610 bb0a18e1 Gerd Hoffmann
                kbd_put_keysym('\n');
1611 bb0a18e1 Gerd Hoffmann
                break;
1612 bb0a18e1 Gerd Hoffmann
1613 64f5a135 bellard
            default:
1614 64f5a135 bellard
                kbd_put_keysym(sym);
1615 64f5a135 bellard
                break;
1616 64f5a135 bellard
            }
1617 64f5a135 bellard
        }
1618 64f5a135 bellard
    }
1619 24236869 bellard
}
1620 24236869 bellard
1621 bdbd7676 bellard
static void key_event(VncState *vs, int down, uint32_t sym)
1622 bdbd7676 bellard
{
1623 9ca313aa aliguori
    int keycode;
1624 4a93fe17 Gerd Hoffmann
    int lsym = sym;
1625 9ca313aa aliguori
1626 4a93fe17 Gerd Hoffmann
    if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) {
1627 4a93fe17 Gerd Hoffmann
        lsym = lsym - 'A' + 'a';
1628 4a93fe17 Gerd Hoffmann
    }
1629 9ca313aa aliguori
1630 44bb61c8 Samuel Thibault
    keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
1631 9ca313aa aliguori
    do_key_event(vs, down, keycode, sym);
1632 9ca313aa aliguori
}
1633 9ca313aa aliguori
1634 9ca313aa aliguori
static void ext_key_event(VncState *vs, int down,
1635 9ca313aa aliguori
                          uint32_t sym, uint16_t keycode)
1636 9ca313aa aliguori
{
1637 9ca313aa aliguori
    /* if the user specifies a keyboard layout, always use it */
1638 9ca313aa aliguori
    if (keyboard_layout)
1639 9ca313aa aliguori
        key_event(vs, down, sym);
1640 9ca313aa aliguori
    else
1641 9ca313aa aliguori
        do_key_event(vs, down, keycode, sym);
1642 bdbd7676 bellard
}
1643 bdbd7676 bellard
1644 24236869 bellard
static void framebuffer_update_request(VncState *vs, int incremental,
1645 28a76be8 aliguori
                                       int x_position, int y_position,
1646 28a76be8 aliguori
                                       int w, int h)
1647 24236869 bellard
{
1648 6ed391bf Wen Congyang
    int i;
1649 6ed391bf Wen Congyang
    const size_t width = ds_get_width(vs->ds) / 16;
1650 6ed391bf Wen Congyang
1651 0e1f5a0c aliguori
    if (y_position > ds_get_height(vs->ds))
1652 0e1f5a0c aliguori
        y_position = ds_get_height(vs->ds);
1653 0e1f5a0c aliguori
    if (y_position + h >= ds_get_height(vs->ds))
1654 0e1f5a0c aliguori
        h = ds_get_height(vs->ds) - y_position;
1655 cf2d385c ths
1656 24236869 bellard
    vs->need_update = 1;
1657 24236869 bellard
    if (!incremental) {
1658 24cf0a6e Gerd Hoffmann
        vs->force_update = 1;
1659 28a76be8 aliguori
        for (i = 0; i < h; i++) {
1660 6ed391bf Wen Congyang
            bitmap_set(vs->dirty[y_position + i], 0, width);
1661 6ed391bf Wen Congyang
            bitmap_clear(vs->dirty[y_position + i], width,
1662 a0843a68 Anthony Liguori
                         VNC_DIRTY_BITS - width);
1663 28a76be8 aliguori
        }
1664 24236869 bellard
    }
1665 24236869 bellard
}
1666 24236869 bellard
1667 9ca313aa aliguori
static void send_ext_key_event_ack(VncState *vs)
1668 9ca313aa aliguori
{
1669 bd023f95 Corentin Chary
    vnc_lock_output(vs);
1670 46a183da Daniel P. Berrange
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1671 9ca313aa aliguori
    vnc_write_u8(vs, 0);
1672 9ca313aa aliguori
    vnc_write_u16(vs, 1);
1673 29fa4ed9 aliguori
    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1674 29fa4ed9 aliguori
                           VNC_ENCODING_EXT_KEY_EVENT);
1675 bd023f95 Corentin Chary
    vnc_unlock_output(vs);
1676 9ca313aa aliguori
    vnc_flush(vs);
1677 9ca313aa aliguori
}
1678 9ca313aa aliguori
1679 429a8ed3 malc
static void send_ext_audio_ack(VncState *vs)
1680 429a8ed3 malc
{
1681 bd023f95 Corentin Chary
    vnc_lock_output(vs);
1682 46a183da Daniel P. Berrange
    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1683 429a8ed3 malc
    vnc_write_u8(vs, 0);
1684 429a8ed3 malc
    vnc_write_u16(vs, 1);
1685 29fa4ed9 aliguori
    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
1686 29fa4ed9 aliguori
                           VNC_ENCODING_AUDIO);
1687 bd023f95 Corentin Chary
    vnc_unlock_output(vs);
1688 429a8ed3 malc
    vnc_flush(vs);
1689 429a8ed3 malc
}
1690 429a8ed3 malc
1691 24236869 bellard
static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
1692 24236869 bellard
{
1693 24236869 bellard
    int i;
1694 29fa4ed9 aliguori
    unsigned int enc = 0;
1695 24236869 bellard
1696 29fa4ed9 aliguori
    vs->features = 0;
1697 a9f20d31 Corentin Chary
    vs->vnc_encoding = 0;
1698 d1af0e05 Corentin Chary
    vs->tight.compression = 9;
1699 d1af0e05 Corentin Chary
    vs->tight.quality = -1; /* Lossless by default */
1700 564c337e bellard
    vs->absolute = -1;
1701 24236869 bellard
1702 8a0f0d0c Corentin Chary
    /*
1703 8a0f0d0c Corentin Chary
     * Start from the end because the encodings are sent in order of preference.
1704 8a0f0d0c Corentin Chary
     * This way the prefered encoding (first encoding defined in the array)
1705 8a0f0d0c Corentin Chary
     * will be set at the end of the loop.
1706 8a0f0d0c Corentin Chary
     */
1707 24236869 bellard
    for (i = n_encodings - 1; i >= 0; i--) {
1708 29fa4ed9 aliguori
        enc = encodings[i];
1709 29fa4ed9 aliguori
        switch (enc) {
1710 29fa4ed9 aliguori
        case VNC_ENCODING_RAW:
1711 a9f20d31 Corentin Chary
            vs->vnc_encoding = enc;
1712 29fa4ed9 aliguori
            break;
1713 29fa4ed9 aliguori
        case VNC_ENCODING_COPYRECT:
1714 753b4053 aliguori
            vs->features |= VNC_FEATURE_COPYRECT_MASK;
1715 29fa4ed9 aliguori
            break;
1716 29fa4ed9 aliguori
        case VNC_ENCODING_HEXTILE:
1717 29fa4ed9 aliguori
            vs->features |= VNC_FEATURE_HEXTILE_MASK;
1718 a9f20d31 Corentin Chary
            vs->vnc_encoding = enc;
1719 29fa4ed9 aliguori
            break;
1720 380282b0 Corentin Chary
        case VNC_ENCODING_TIGHT:
1721 380282b0 Corentin Chary
            vs->features |= VNC_FEATURE_TIGHT_MASK;
1722 380282b0 Corentin Chary
            vs->vnc_encoding = enc;
1723 380282b0 Corentin Chary
            break;
1724 efe556ad Corentin Chary
        case VNC_ENCODING_TIGHT_PNG:
1725 efe556ad Corentin Chary
            vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
1726 efe556ad Corentin Chary
            vs->vnc_encoding = enc;
1727 efe556ad Corentin Chary
            break;
1728 059cef40 aliguori
        case VNC_ENCODING_ZLIB:
1729 059cef40 aliguori
            vs->features |= VNC_FEATURE_ZLIB_MASK;
1730 a9f20d31 Corentin Chary
            vs->vnc_encoding = enc;
1731 059cef40 aliguori
            break;
1732 148954fa Corentin Chary
        case VNC_ENCODING_ZRLE:
1733 148954fa Corentin Chary
            vs->features |= VNC_FEATURE_ZRLE_MASK;
1734 148954fa Corentin Chary
            vs->vnc_encoding = enc;
1735 148954fa Corentin Chary
            break;
1736 148954fa Corentin Chary
        case VNC_ENCODING_ZYWRLE:
1737 148954fa Corentin Chary
            vs->features |= VNC_FEATURE_ZYWRLE_MASK;
1738 148954fa Corentin Chary
            vs->vnc_encoding = enc;
1739 148954fa Corentin Chary
            break;
1740 29fa4ed9 aliguori
        case VNC_ENCODING_DESKTOPRESIZE:
1741 29fa4ed9 aliguori
            vs->features |= VNC_FEATURE_RESIZE_MASK;
1742 29fa4ed9 aliguori
            break;
1743 29fa4ed9 aliguori
        case VNC_ENCODING_POINTER_TYPE_CHANGE:
1744 29fa4ed9 aliguori
            vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK;
1745 29fa4ed9 aliguori
            break;
1746 d467b679 Gerd Hoffmann
        case VNC_ENCODING_RICH_CURSOR:
1747 d467b679 Gerd Hoffmann
            vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
1748 d467b679 Gerd Hoffmann
            break;
1749 29fa4ed9 aliguori
        case VNC_ENCODING_EXT_KEY_EVENT:
1750 9ca313aa aliguori
            send_ext_key_event_ack(vs);
1751 9ca313aa aliguori
            break;
1752 29fa4ed9 aliguori
        case VNC_ENCODING_AUDIO:
1753 429a8ed3 malc
            send_ext_audio_ack(vs);
1754 429a8ed3 malc
            break;
1755 29fa4ed9 aliguori
        case VNC_ENCODING_WMVi:
1756 29fa4ed9 aliguori
            vs->features |= VNC_FEATURE_WMVI_MASK;
1757 ca4cca4d aliguori
            break;
1758 fb437313 aliguori
        case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
1759 d1af0e05 Corentin Chary
            vs->tight.compression = (enc & 0x0F);
1760 fb437313 aliguori
            break;
1761 fb437313 aliguori
        case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
1762 b31f519e Corentin Chary
            if (vs->vd->lossy) {
1763 b31f519e Corentin Chary
                vs->tight.quality = (enc & 0x0F);
1764 b31f519e Corentin Chary
            }
1765 fb437313 aliguori
            break;
1766 29fa4ed9 aliguori
        default:
1767 29fa4ed9 aliguori
            VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
1768 29fa4ed9 aliguori
            break;
1769 29fa4ed9 aliguori
        }
1770 24236869 bellard
    }
1771 6356e472 Gerd Hoffmann
    vnc_desktop_resize(vs);
1772 0684bf1b Anthony Liguori
    check_pointer_type_change(&vs->mouse_mode_notifier);
1773 24236869 bellard
}
1774 24236869 bellard
1775 6cec5487 aliguori
static void set_pixel_conversion(VncState *vs)
1776 6cec5487 aliguori
{
1777 6cec5487 aliguori
    if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
1778 6cec5487 aliguori
        (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && 
1779 6cec5487 aliguori
        !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
1780 6cec5487 aliguori
        vs->write_pixels = vnc_write_pixels_copy;
1781 70a4568f Corentin Chary
        vnc_hextile_set_pixel_conversion(vs, 0);
1782 6cec5487 aliguori
    } else {
1783 6cec5487 aliguori
        vs->write_pixels = vnc_write_pixels_generic;
1784 70a4568f Corentin Chary
        vnc_hextile_set_pixel_conversion(vs, 1);
1785 6cec5487 aliguori
    }
1786 6cec5487 aliguori
}
1787 6cec5487 aliguori
1788 24236869 bellard
static void set_pixel_format(VncState *vs,
1789 28a76be8 aliguori
                             int bits_per_pixel, int depth,
1790 28a76be8 aliguori
                             int big_endian_flag, int true_color_flag,
1791 28a76be8 aliguori
                             int red_max, int green_max, int blue_max,
1792 28a76be8 aliguori
                             int red_shift, int green_shift, int blue_shift)
1793 24236869 bellard
{
1794 3512779a bellard
    if (!true_color_flag) {
1795 28a76be8 aliguori
        vnc_client_error(vs);
1796 3512779a bellard
        return;
1797 3512779a bellard
    }
1798 24236869 bellard
1799 1fc62412 Stefano Stabellini
    vs->clientds = *(vs->vd->guest.ds);
1800 6cec5487 aliguori
    vs->clientds.pf.rmax = red_max;
1801 bc2429b9 Corentin Chary
    vs->clientds.pf.rbits = hweight_long(red_max);
1802 6cec5487 aliguori
    vs->clientds.pf.rshift = red_shift;
1803 6cec5487 aliguori
    vs->clientds.pf.rmask = red_max << red_shift;
1804 6cec5487 aliguori
    vs->clientds.pf.gmax = green_max;
1805 bc2429b9 Corentin Chary
    vs->clientds.pf.gbits = hweight_long(green_max);
1806 6cec5487 aliguori
    vs->clientds.pf.gshift = green_shift;
1807 6cec5487 aliguori
    vs->clientds.pf.gmask = green_max << green_shift;
1808 6cec5487 aliguori
    vs->clientds.pf.bmax = blue_max;
1809 bc2429b9 Corentin Chary
    vs->clientds.pf.bbits = hweight_long(blue_max);
1810 6cec5487 aliguori
    vs->clientds.pf.bshift = blue_shift;
1811 6cec5487 aliguori
    vs->clientds.pf.bmask = blue_max << blue_shift;
1812 6cec5487 aliguori
    vs->clientds.pf.bits_per_pixel = bits_per_pixel;
1813 6cec5487 aliguori
    vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
1814 6cec5487 aliguori
    vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
1815 6cec5487 aliguori
    vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
1816 6cec5487 aliguori
1817 6cec5487 aliguori
    set_pixel_conversion(vs);
1818 24236869 bellard
1819 24236869 bellard
    vga_hw_invalidate();
1820 24236869 bellard
    vga_hw_update();
1821 24236869 bellard
}
1822 24236869 bellard
1823 ca4cca4d aliguori
static void pixel_format_message (VncState *vs) {
1824 ca4cca4d aliguori
    char pad[3] = { 0, 0, 0 };
1825 ca4cca4d aliguori
1826 6cec5487 aliguori
    vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
1827 6cec5487 aliguori
    vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
1828 ca4cca4d aliguori
1829 e2542fe2 Juan Quintela
#ifdef HOST_WORDS_BIGENDIAN
1830 ca4cca4d aliguori
    vnc_write_u8(vs, 1);             /* big-endian-flag */
1831 ca4cca4d aliguori
#else
1832 ca4cca4d aliguori
    vnc_write_u8(vs, 0);             /* big-endian-flag */
1833 ca4cca4d aliguori
#endif
1834 ca4cca4d aliguori
    vnc_write_u8(vs, 1);             /* true-color-flag */
1835 6cec5487 aliguori
    vnc_write_u16(vs, vs->ds->surface->pf.rmax);     /* red-max */
1836 6cec5487 aliguori
    vnc_write_u16(vs, vs->ds->surface->pf.gmax);     /* green-max */
1837 6cec5487 aliguori
    vnc_write_u16(vs, vs->ds->surface->pf.bmax);     /* blue-max */
1838 6cec5487 aliguori
    vnc_write_u8(vs, vs->ds->surface->pf.rshift);    /* red-shift */
1839 6cec5487 aliguori
    vnc_write_u8(vs, vs->ds->surface->pf.gshift);    /* green-shift */
1840 6cec5487 aliguori
    vnc_write_u8(vs, vs->ds->surface->pf.bshift);    /* blue-shift */
1841 70a4568f Corentin Chary
1842 70a4568f Corentin Chary
    vnc_hextile_set_pixel_conversion(vs, 0);
1843 70a4568f Corentin Chary
1844 6cec5487 aliguori
    vs->clientds = *(vs->ds->surface);
1845 3cded540 aurel32
    vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
1846 ca4cca4d aliguori
    vs->write_pixels = vnc_write_pixels_copy;
1847 ca4cca4d aliguori
1848 ca4cca4d aliguori
    vnc_write(vs, pad, 3);           /* padding */
1849 ca4cca4d aliguori
}
1850 ca4cca4d aliguori
1851 7d957bd8 aliguori
static void vnc_dpy_setdata(DisplayState *ds)
1852 7d957bd8 aliguori
{
1853 7d957bd8 aliguori
    /* We don't have to do anything */
1854 7d957bd8 aliguori
}
1855 7d957bd8 aliguori
1856 753b4053 aliguori
static void vnc_colordepth(VncState *vs)
1857 7eac3a87 aliguori
{
1858 753b4053 aliguori
    if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
1859 ca4cca4d aliguori
        /* Sending a WMVi message to notify the client*/
1860 bd023f95 Corentin Chary
        vnc_lock_output(vs);
1861 46a183da Daniel P. Berrange
        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
1862 ca4cca4d aliguori
        vnc_write_u8(vs, 0);
1863 ca4cca4d aliguori
        vnc_write_u16(vs, 1); /* number of rects */
1864 753b4053 aliguori
        vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), 
1865 753b4053 aliguori
                               ds_get_height(vs->ds), VNC_ENCODING_WMVi);
1866 ca4cca4d aliguori
        pixel_format_message(vs);
1867 bd023f95 Corentin Chary
        vnc_unlock_output(vs);
1868 ca4cca4d aliguori
        vnc_flush(vs);
1869 7eac3a87 aliguori
    } else {
1870 6cec5487 aliguori
        set_pixel_conversion(vs);
1871 7eac3a87 aliguori
    }
1872 7eac3a87 aliguori
}
1873 7eac3a87 aliguori
1874 60fe76f3 ths
static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
1875 24236869 bellard
{
1876 24236869 bellard
    int i;
1877 24236869 bellard
    uint16_t limit;
1878 2430ffe4 Stefano Stabellini
    VncDisplay *vd = vs->vd;
1879 2430ffe4 Stefano Stabellini
1880 2430ffe4 Stefano Stabellini
    if (data[0] > 3) {
1881 2430ffe4 Stefano Stabellini
        vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
1882 7bd427d8 Paolo Bonzini
        if (!qemu_timer_expired(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval))
1883 7bd427d8 Paolo Bonzini
            qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval);
1884 2430ffe4 Stefano Stabellini
    }
1885 24236869 bellard
1886 24236869 bellard
    switch (data[0]) {
1887 46a183da Daniel P. Berrange
    case VNC_MSG_CLIENT_SET_PIXEL_FORMAT:
1888 28a76be8 aliguori
        if (len == 1)
1889 28a76be8 aliguori
            return 20;
1890 28a76be8 aliguori
1891 28a76be8 aliguori
        set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5),
1892 28a76be8 aliguori
                         read_u8(data, 6), read_u8(data, 7),
1893 28a76be8 aliguori
                         read_u16(data, 8), read_u16(data, 10),
1894 28a76be8 aliguori
                         read_u16(data, 12), read_u8(data, 14),
1895 28a76be8 aliguori
                         read_u8(data, 15), read_u8(data, 16));
1896 28a76be8 aliguori
        break;
1897 46a183da Daniel P. Berrange
    case VNC_MSG_CLIENT_SET_ENCODINGS:
1898 28a76be8 aliguori
        if (len == 1)
1899 28a76be8 aliguori
            return 4;
1900 24236869 bellard
1901 28a76be8 aliguori
        if (len == 4) {
1902 69dd5c9f aliguori
            limit = read_u16(data, 2);
1903 69dd5c9f aliguori
            if (limit > 0)
1904 69dd5c9f aliguori
                return 4 + (limit * 4);
1905 69dd5c9f aliguori
        } else
1906 69dd5c9f aliguori
            limit = read_u16(data, 2);
1907 24236869 bellard
1908 28a76be8 aliguori
        for (i = 0; i < limit; i++) {
1909 28a76be8 aliguori
            int32_t val = read_s32(data, 4 + (i * 4));
1910 28a76be8 aliguori
            memcpy(data + 4 + (i * 4), &val, sizeof(val));
1911 28a76be8 aliguori
        }
1912 24236869 bellard
1913 28a76be8 aliguori
        set_encodings(vs, (int32_t *)(data + 4), limit);
1914 28a76be8 aliguori
        break;
1915 46a183da Daniel P. Berrange
    case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST:
1916 28a76be8 aliguori
        if (len == 1)
1917 28a76be8 aliguori
            return 10;
1918 24236869 bellard
1919 28a76be8 aliguori
        framebuffer_update_request(vs,
1920 28a76be8 aliguori
                                   read_u8(data, 1), read_u16(data, 2), read_u16(data, 4),
1921 28a76be8 aliguori
                                   read_u16(data, 6), read_u16(data, 8));
1922 28a76be8 aliguori
        break;
1923 46a183da Daniel P. Berrange
    case VNC_MSG_CLIENT_KEY_EVENT:
1924 28a76be8 aliguori
        if (len == 1)
1925 28a76be8 aliguori
            return 8;
1926 24236869 bellard
1927 28a76be8 aliguori
        key_event(vs, read_u8(data, 1), read_u32(data, 4));
1928 28a76be8 aliguori
        break;
1929 46a183da Daniel P. Berrange
    case VNC_MSG_CLIENT_POINTER_EVENT:
1930 28a76be8 aliguori
        if (len == 1)
1931 28a76be8 aliguori
            return 6;
1932 24236869 bellard
1933 28a76be8 aliguori
        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
1934 28a76be8 aliguori
        break;
1935 46a183da Daniel P. Berrange
    case VNC_MSG_CLIENT_CUT_TEXT:
1936 28a76be8 aliguori
        if (len == 1)
1937 28a76be8 aliguori
            return 8;
1938 24236869 bellard
1939 28a76be8 aliguori
        if (len == 8) {
1940 baa7666c ths
            uint32_t dlen = read_u32(data, 4);
1941 baa7666c ths
            if (dlen > 0)
1942 baa7666c ths
                return 8 + dlen;
1943 baa7666c ths
        }
1944 24236869 bellard
1945 28a76be8 aliguori
        client_cut_text(vs, read_u32(data, 4), data + 8);
1946 28a76be8 aliguori
        break;
1947 46a183da Daniel P. Berrange
    case VNC_MSG_CLIENT_QEMU:
1948 9ca313aa aliguori
        if (len == 1)
1949 9ca313aa aliguori
            return 2;
1950 9ca313aa aliguori
1951 9ca313aa aliguori
        switch (read_u8(data, 1)) {
1952 46a183da Daniel P. Berrange
        case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT:
1953 9ca313aa aliguori
            if (len == 2)
1954 9ca313aa aliguori
                return 12;
1955 9ca313aa aliguori
1956 9ca313aa aliguori
            ext_key_event(vs, read_u16(data, 2),
1957 9ca313aa aliguori
                          read_u32(data, 4), read_u32(data, 8));
1958 9ca313aa aliguori
            break;
1959 46a183da Daniel P. Berrange
        case VNC_MSG_CLIENT_QEMU_AUDIO:
1960 429a8ed3 malc
            if (len == 2)
1961 429a8ed3 malc
                return 4;
1962 429a8ed3 malc
1963 429a8ed3 malc
            switch (read_u16 (data, 2)) {
1964 46a183da Daniel P. Berrange
            case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE:
1965 429a8ed3 malc
                audio_add(vs);
1966 429a8ed3 malc
                break;
1967 46a183da Daniel P. Berrange
            case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE:
1968 429a8ed3 malc
                audio_del(vs);
1969 429a8ed3 malc
                break;
1970 46a183da Daniel P. Berrange
            case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT:
1971 429a8ed3 malc
                if (len == 4)
1972 429a8ed3 malc
                    return 10;
1973 429a8ed3 malc
                switch (read_u8(data, 4)) {
1974 429a8ed3 malc
                case 0: vs->as.fmt = AUD_FMT_U8; break;
1975 429a8ed3 malc
                case 1: vs->as.fmt = AUD_FMT_S8; break;
1976 429a8ed3 malc
                case 2: vs->as.fmt = AUD_FMT_U16; break;
1977 429a8ed3 malc
                case 3: vs->as.fmt = AUD_FMT_S16; break;
1978 429a8ed3 malc
                case 4: vs->as.fmt = AUD_FMT_U32; break;
1979 429a8ed3 malc
                case 5: vs->as.fmt = AUD_FMT_S32; break;
1980 429a8ed3 malc
                default:
1981 429a8ed3 malc
                    printf("Invalid audio format %d\n", read_u8(data, 4));
1982 429a8ed3 malc
                    vnc_client_error(vs);
1983 429a8ed3 malc
                    break;
1984 429a8ed3 malc
                }
1985 429a8ed3 malc
                vs->as.nchannels = read_u8(data, 5);
1986 429a8ed3 malc
                if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
1987 429a8ed3 malc
                    printf("Invalid audio channel coount %d\n",
1988 429a8ed3 malc
                           read_u8(data, 5));
1989 429a8ed3 malc
                    vnc_client_error(vs);
1990 429a8ed3 malc
                    break;
1991 429a8ed3 malc
                }
1992 429a8ed3 malc
                vs->as.freq = read_u32(data, 6);
1993 429a8ed3 malc
                break;
1994 429a8ed3 malc
            default:
1995 429a8ed3 malc
                printf ("Invalid audio message %d\n", read_u8(data, 4));
1996 429a8ed3 malc
                vnc_client_error(vs);
1997 429a8ed3 malc
                break;
1998 429a8ed3 malc
            }
1999 429a8ed3 malc
            break;
2000 429a8ed3 malc
2001 9ca313aa aliguori
        default:
2002 9ca313aa aliguori
            printf("Msg: %d\n", read_u16(data, 0));
2003 9ca313aa aliguori
            vnc_client_error(vs);
2004 9ca313aa aliguori
            break;
2005 9ca313aa aliguori
        }
2006 9ca313aa aliguori
        break;
2007 24236869 bellard
    default:
2008 28a76be8 aliguori
        printf("Msg: %d\n", data[0]);
2009 28a76be8 aliguori
        vnc_client_error(vs);
2010 28a76be8 aliguori
        break;
2011 24236869 bellard
    }
2012 5fafdf24 ths
2013 24236869 bellard
    vnc_read_when(vs, protocol_client_msg, 1);
2014 24236869 bellard
    return 0;
2015 24236869 bellard
}
2016 24236869 bellard
2017 60fe76f3 ths
static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
2018 24236869 bellard
{
2019 c35734b2 ths
    char buf[1024];
2020 c35734b2 ths
    int size;
2021 24236869 bellard
2022 5862d195 Gerd Hoffmann
    vs->client_width = ds_get_width(vs->ds);
2023 5862d195 Gerd Hoffmann
    vs->client_height = ds_get_height(vs->ds);
2024 5862d195 Gerd Hoffmann
    vnc_write_u16(vs, vs->client_width);
2025 5862d195 Gerd Hoffmann
    vnc_write_u16(vs, vs->client_height);
2026 24236869 bellard
2027 ca4cca4d aliguori
    pixel_format_message(vs);
2028 24236869 bellard
2029 c35734b2 ths
    if (qemu_name)
2030 c35734b2 ths
        size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
2031 c35734b2 ths
    else
2032 c35734b2 ths
        size = snprintf(buf, sizeof(buf), "QEMU");
2033 c35734b2 ths
2034 c35734b2 ths
    vnc_write_u32(vs, size);
2035 c35734b2 ths
    vnc_write(vs, buf, size);
2036 24236869 bellard
    vnc_flush(vs);
2037 24236869 bellard
2038 4a80dba3 Luiz Capitulino
    vnc_client_cache_auth(vs);
2039 0d2ed46a Luiz Capitulino
    vnc_qmp_event(vs, QEVENT_VNC_INITIALIZED);
2040 4a80dba3 Luiz Capitulino
2041 24236869 bellard
    vnc_read_when(vs, protocol_client_msg, 1);
2042 24236869 bellard
2043 24236869 bellard
    return 0;
2044 24236869 bellard
}
2045 24236869 bellard
2046 5fb6c7a8 aliguori
void start_client_init(VncState *vs)
2047 5fb6c7a8 aliguori
{
2048 5fb6c7a8 aliguori
    vnc_read_when(vs, protocol_client_init, 1);
2049 5fb6c7a8 aliguori
}
2050 5fb6c7a8 aliguori
2051 70848515 ths
static void make_challenge(VncState *vs)
2052 70848515 ths
{
2053 70848515 ths
    int i;
2054 70848515 ths
2055 70848515 ths
    srand(time(NULL)+getpid()+getpid()*987654+rand());
2056 70848515 ths
2057 70848515 ths
    for (i = 0 ; i < sizeof(vs->challenge) ; i++)
2058 70848515 ths
        vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
2059 70848515 ths
}
2060 70848515 ths
2061 60fe76f3 ths
static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
2062 70848515 ths
{
2063 60fe76f3 ths
    unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
2064 70848515 ths
    int i, j, pwlen;
2065 60fe76f3 ths
    unsigned char key[8];
2066 3c9405a0 Gerd Hoffmann
    time_t now = time(NULL);
2067 70848515 ths
2068 1cd20f8b Anthony Liguori
    if (!vs->vd->password) {
2069 28a76be8 aliguori
        VNC_DEBUG("No password configured on server");
2070 6bffdf0f Gerd Hoffmann
        goto reject;
2071 70848515 ths
    }
2072 3c9405a0 Gerd Hoffmann
    if (vs->vd->expires < now) {
2073 3c9405a0 Gerd Hoffmann
        VNC_DEBUG("Password is expired");
2074 3c9405a0 Gerd Hoffmann
        goto reject;
2075 3c9405a0 Gerd Hoffmann
    }
2076 70848515 ths
2077 70848515 ths
    memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
2078 70848515 ths
2079 70848515 ths
    /* Calculate the expected challenge response */
2080 753b4053 aliguori
    pwlen = strlen(vs->vd->password);
2081 70848515 ths
    for (i=0; i<sizeof(key); i++)
2082 753b4053 aliguori
        key[i] = i<pwlen ? vs->vd->password[i] : 0;
2083 70848515 ths
    deskey(key, EN0);
2084 70848515 ths
    for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
2085 70848515 ths
        des(response+j, response+j);
2086 70848515 ths
2087 70848515 ths
    /* Compare expected vs actual challenge response */
2088 70848515 ths
    if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
2089 28a76be8 aliguori
        VNC_DEBUG("Client challenge reponse did not match\n");
2090 6bffdf0f Gerd Hoffmann
        goto reject;
2091 70848515 ths
    } else {
2092 28a76be8 aliguori
        VNC_DEBUG("Accepting VNC challenge response\n");
2093 28a76be8 aliguori
        vnc_write_u32(vs, 0); /* Accept auth */
2094 28a76be8 aliguori
        vnc_flush(vs);
2095 70848515 ths
2096 5fb6c7a8 aliguori
        start_client_init(vs);
2097 70848515 ths
    }
2098 70848515 ths
    return 0;
2099 6bffdf0f Gerd Hoffmann
2100 6bffdf0f Gerd Hoffmann
reject:
2101 6bffdf0f Gerd Hoffmann
    vnc_write_u32(vs, 1); /* Reject auth */
2102 6bffdf0f Gerd Hoffmann
    if (vs->minor >= 8) {
2103 6bffdf0f Gerd Hoffmann
        static const char err[] = "Authentication failed";
2104 6bffdf0f Gerd Hoffmann
        vnc_write_u32(vs, sizeof(err));
2105 6bffdf0f Gerd Hoffmann
        vnc_write(vs, err, sizeof(err));
2106 6bffdf0f Gerd Hoffmann
    }
2107 6bffdf0f Gerd Hoffmann
    vnc_flush(vs);
2108 6bffdf0f Gerd Hoffmann
    vnc_client_error(vs);
2109 6bffdf0f Gerd Hoffmann
    return 0;
2110 70848515 ths
}
2111 70848515 ths
2112 5fb6c7a8 aliguori
void start_auth_vnc(VncState *vs)
2113 70848515 ths
{
2114 70848515 ths
    make_challenge(vs);
2115 70848515 ths
    /* Send client a 'random' challenge */
2116 70848515 ths
    vnc_write(vs, vs->challenge, sizeof(vs->challenge));
2117 70848515 ths
    vnc_flush(vs);
2118 70848515 ths
2119 70848515 ths
    vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
2120 469b15c6 ths
}
2121 469b15c6 ths
2122 469b15c6 ths
2123 60fe76f3 ths
static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
2124 70848515 ths
{
2125 70848515 ths
    /* We only advertise 1 auth scheme at a time, so client
2126 70848515 ths
     * must pick the one we sent. Verify this */
2127 753b4053 aliguori
    if (data[0] != vs->vd->auth) { /* Reject auth */
2128 1263b7d6 aliguori
       VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]);
2129 70848515 ths
       vnc_write_u32(vs, 1);
2130 70848515 ths
       if (vs->minor >= 8) {
2131 70848515 ths
           static const char err[] = "Authentication failed";
2132 70848515 ths
           vnc_write_u32(vs, sizeof(err));
2133 70848515 ths
           vnc_write(vs, err, sizeof(err));
2134 70848515 ths
       }
2135 70848515 ths
       vnc_client_error(vs);
2136 70848515 ths
    } else { /* Accept requested auth */
2137 70848515 ths
       VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
2138 753b4053 aliguori
       switch (vs->vd->auth) {
2139 70848515 ths
       case VNC_AUTH_NONE:
2140 70848515 ths
           VNC_DEBUG("Accept auth none\n");
2141 a26c97ad balrog
           if (vs->minor >= 8) {
2142 a26c97ad balrog
               vnc_write_u32(vs, 0); /* Accept auth completion */
2143 a26c97ad balrog
               vnc_flush(vs);
2144 a26c97ad balrog
           }
2145 5fb6c7a8 aliguori
           start_client_init(vs);
2146 70848515 ths
           break;
2147 70848515 ths
2148 70848515 ths
       case VNC_AUTH_VNC:
2149 70848515 ths
           VNC_DEBUG("Start VNC auth\n");
2150 5fb6c7a8 aliguori
           start_auth_vnc(vs);
2151 5fb6c7a8 aliguori
           break;
2152 70848515 ths
2153 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
2154 8d5d2d4c ths
       case VNC_AUTH_VENCRYPT:
2155 8d5d2d4c ths
           VNC_DEBUG("Accept VeNCrypt auth\n");;
2156 5fb6c7a8 aliguori
           start_auth_vencrypt(vs);
2157 5fb6c7a8 aliguori
           break;
2158 8d5d2d4c ths
#endif /* CONFIG_VNC_TLS */
2159 8d5d2d4c ths
2160 2f9606b3 aliguori
#ifdef CONFIG_VNC_SASL
2161 2f9606b3 aliguori
       case VNC_AUTH_SASL:
2162 2f9606b3 aliguori
           VNC_DEBUG("Accept SASL auth\n");
2163 2f9606b3 aliguori
           start_auth_sasl(vs);
2164 2f9606b3 aliguori
           break;
2165 2f9606b3 aliguori
#endif /* CONFIG_VNC_SASL */
2166 2f9606b3 aliguori
2167 70848515 ths
       default: /* Should not be possible, but just in case */
2168 1263b7d6 aliguori
           VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth);
2169 70848515 ths
           vnc_write_u8(vs, 1);
2170 70848515 ths
           if (vs->minor >= 8) {
2171 70848515 ths
               static const char err[] = "Authentication failed";
2172 70848515 ths
               vnc_write_u32(vs, sizeof(err));
2173 70848515 ths
               vnc_write(vs, err, sizeof(err));
2174 70848515 ths
           }
2175 70848515 ths
           vnc_client_error(vs);
2176 70848515 ths
       }
2177 70848515 ths
    }
2178 70848515 ths
    return 0;
2179 70848515 ths
}
2180 70848515 ths
2181 60fe76f3 ths
static int protocol_version(VncState *vs, uint8_t *version, size_t len)
2182 24236869 bellard
{
2183 24236869 bellard
    char local[13];
2184 24236869 bellard
2185 24236869 bellard
    memcpy(local, version, 12);
2186 24236869 bellard
    local[12] = 0;
2187 24236869 bellard
2188 70848515 ths
    if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
2189 28a76be8 aliguori
        VNC_DEBUG("Malformed protocol version %s\n", local);
2190 28a76be8 aliguori
        vnc_client_error(vs);
2191 28a76be8 aliguori
        return 0;
2192 24236869 bellard
    }
2193 70848515 ths
    VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
2194 70848515 ths
    if (vs->major != 3 ||
2195 28a76be8 aliguori
        (vs->minor != 3 &&
2196 28a76be8 aliguori
         vs->minor != 4 &&
2197 28a76be8 aliguori
         vs->minor != 5 &&
2198 28a76be8 aliguori
         vs->minor != 7 &&
2199 28a76be8 aliguori
         vs->minor != 8)) {
2200 28a76be8 aliguori
        VNC_DEBUG("Unsupported client version\n");
2201 28a76be8 aliguori
        vnc_write_u32(vs, VNC_AUTH_INVALID);
2202 28a76be8 aliguori
        vnc_flush(vs);
2203 28a76be8 aliguori
        vnc_client_error(vs);
2204 28a76be8 aliguori
        return 0;
2205 70848515 ths
    }
2206 b0566f4f ths
    /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
2207 70848515 ths
     * as equivalent to v3.3 by servers
2208 70848515 ths
     */
2209 b0566f4f ths
    if (vs->minor == 4 || vs->minor == 5)
2210 28a76be8 aliguori
        vs->minor = 3;
2211 70848515 ths
2212 70848515 ths
    if (vs->minor == 3) {
2213 28a76be8 aliguori
        if (vs->vd->auth == VNC_AUTH_NONE) {
2214 70848515 ths
            VNC_DEBUG("Tell client auth none\n");
2215 753b4053 aliguori
            vnc_write_u32(vs, vs->vd->auth);
2216 70848515 ths
            vnc_flush(vs);
2217 28a76be8 aliguori
            start_client_init(vs);
2218 753b4053 aliguori
       } else if (vs->vd->auth == VNC_AUTH_VNC) {
2219 70848515 ths
            VNC_DEBUG("Tell client VNC auth\n");
2220 753b4053 aliguori
            vnc_write_u32(vs, vs->vd->auth);
2221 70848515 ths
            vnc_flush(vs);
2222 70848515 ths
            start_auth_vnc(vs);
2223 70848515 ths
       } else {
2224 753b4053 aliguori
            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
2225 70848515 ths
            vnc_write_u32(vs, VNC_AUTH_INVALID);
2226 70848515 ths
            vnc_flush(vs);
2227 70848515 ths
            vnc_client_error(vs);
2228 70848515 ths
       }
2229 70848515 ths
    } else {
2230 28a76be8 aliguori
        VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
2231 28a76be8 aliguori
        vnc_write_u8(vs, 1); /* num auth */
2232 28a76be8 aliguori
        vnc_write_u8(vs, vs->vd->auth);
2233 28a76be8 aliguori
        vnc_read_when(vs, protocol_client_auth, 1);
2234 28a76be8 aliguori
        vnc_flush(vs);
2235 70848515 ths
    }
2236 24236869 bellard
2237 24236869 bellard
    return 0;
2238 24236869 bellard
}
2239 24236869 bellard
2240 999342a0 Corentin Chary
static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
2241 999342a0 Corentin Chary
{
2242 999342a0 Corentin Chary
    struct VncSurface *vs = &vd->guest;
2243 999342a0 Corentin Chary
2244 999342a0 Corentin Chary
    return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
2245 999342a0 Corentin Chary
}
2246 999342a0 Corentin Chary
2247 7d964c9d Corentin Chary
void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h)
2248 7d964c9d Corentin Chary
{
2249 7d964c9d Corentin Chary
    int i, j;
2250 7d964c9d Corentin Chary
2251 7d964c9d Corentin Chary
    w = (x + w) / VNC_STAT_RECT;
2252 7d964c9d Corentin Chary
    h = (y + h) / VNC_STAT_RECT;
2253 7d964c9d Corentin Chary
    x /= VNC_STAT_RECT;
2254 7d964c9d Corentin Chary
    y /= VNC_STAT_RECT;
2255 7d964c9d Corentin Chary
2256 207f328a Corentin Chary
    for (j = y; j <= h; j++) {
2257 207f328a Corentin Chary
        for (i = x; i <= w; i++) {
2258 7d964c9d Corentin Chary
            vs->lossy_rect[j][i] = 1;
2259 7d964c9d Corentin Chary
        }
2260 7d964c9d Corentin Chary
    }
2261 7d964c9d Corentin Chary
}
2262 7d964c9d Corentin Chary
2263 7d964c9d Corentin Chary
static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
2264 7d964c9d Corentin Chary
{
2265 7d964c9d Corentin Chary
    VncState *vs;
2266 7d964c9d Corentin Chary
    int sty = y / VNC_STAT_RECT;
2267 7d964c9d Corentin Chary
    int stx = x / VNC_STAT_RECT;
2268 7d964c9d Corentin Chary
    int has_dirty = 0;
2269 7d964c9d Corentin Chary
2270 7d964c9d Corentin Chary
    y = y / VNC_STAT_RECT * VNC_STAT_RECT;
2271 7d964c9d Corentin Chary
    x = x / VNC_STAT_RECT * VNC_STAT_RECT;
2272 7d964c9d Corentin Chary
2273 7d964c9d Corentin Chary
    QTAILQ_FOREACH(vs, &vd->clients, next) {
2274 bc2429b9 Corentin Chary
        int j;
2275 7d964c9d Corentin Chary
2276 7d964c9d Corentin Chary
        /* kernel send buffers are full -> refresh later */
2277 7d964c9d Corentin Chary
        if (vs->output.offset) {
2278 7d964c9d Corentin Chary
            continue;
2279 7d964c9d Corentin Chary
        }
2280 7d964c9d Corentin Chary
2281 7d964c9d Corentin Chary
        if (!vs->lossy_rect[sty][stx]) {
2282 7d964c9d Corentin Chary
            continue;
2283 7d964c9d Corentin Chary
        }
2284 207f328a Corentin Chary
2285 7d964c9d Corentin Chary
        vs->lossy_rect[sty][stx] = 0;
2286 7d964c9d Corentin Chary
        for (j = 0; j < VNC_STAT_RECT; ++j) {
2287 bc2429b9 Corentin Chary
            bitmap_set(vs->dirty[y + j], x / 16, VNC_STAT_RECT / 16);
2288 7d964c9d Corentin Chary
        }
2289 7d964c9d Corentin Chary
        has_dirty++;
2290 7d964c9d Corentin Chary
    }
2291 207f328a Corentin Chary
2292 7d964c9d Corentin Chary
    return has_dirty;
2293 7d964c9d Corentin Chary
}
2294 7d964c9d Corentin Chary
2295 7d964c9d Corentin Chary
static int vnc_update_stats(VncDisplay *vd,  struct timeval * tv)
2296 999342a0 Corentin Chary
{
2297 999342a0 Corentin Chary
    int x, y;
2298 999342a0 Corentin Chary
    struct timeval res;
2299 7d964c9d Corentin Chary
    int has_dirty = 0;
2300 999342a0 Corentin Chary
2301 999342a0 Corentin Chary
    for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
2302 999342a0 Corentin Chary
        for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
2303 999342a0 Corentin Chary
            VncRectStat *rect = vnc_stat_rect(vd, x, y);
2304 999342a0 Corentin Chary
2305 999342a0 Corentin Chary
            rect->updated = false;
2306 999342a0 Corentin Chary
        }
2307 999342a0 Corentin Chary
    }
2308 999342a0 Corentin Chary
2309 ad620c29 Blue Swirl
    qemu_timersub(tv, &VNC_REFRESH_STATS, &res);
2310 999342a0 Corentin Chary
2311 999342a0 Corentin Chary
    if (timercmp(&vd->guest.last_freq_check, &res, >)) {
2312 7d964c9d Corentin Chary
        return has_dirty;
2313 999342a0 Corentin Chary
    }
2314 999342a0 Corentin Chary
    vd->guest.last_freq_check = *tv;
2315 999342a0 Corentin Chary
2316 999342a0 Corentin Chary
    for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
2317 999342a0 Corentin Chary
        for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
2318 999342a0 Corentin Chary
            VncRectStat *rect= vnc_stat_rect(vd, x, y);
2319 999342a0 Corentin Chary
            int count = ARRAY_SIZE(rect->times);
2320 999342a0 Corentin Chary
            struct timeval min, max;
2321 999342a0 Corentin Chary
2322 999342a0 Corentin Chary
            if (!timerisset(&rect->times[count - 1])) {
2323 999342a0 Corentin Chary
                continue ;
2324 999342a0 Corentin Chary
            }
2325 999342a0 Corentin Chary
2326 999342a0 Corentin Chary
            max = rect->times[(rect->idx + count - 1) % count];
2327 ad620c29 Blue Swirl
            qemu_timersub(tv, &max, &res);
2328 999342a0 Corentin Chary
2329 999342a0 Corentin Chary
            if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) {
2330 999342a0 Corentin Chary
                rect->freq = 0;
2331 7d964c9d Corentin Chary
                has_dirty += vnc_refresh_lossy_rect(vd, x, y);
2332 999342a0 Corentin Chary
                memset(rect->times, 0, sizeof (rect->times));
2333 999342a0 Corentin Chary
                continue ;
2334 999342a0 Corentin Chary
            }
2335 999342a0 Corentin Chary
2336 999342a0 Corentin Chary
            min = rect->times[rect->idx];
2337 999342a0 Corentin Chary
            max = rect->times[(rect->idx + count - 1) % count];
2338 ad620c29 Blue Swirl
            qemu_timersub(&max, &min, &res);
2339 999342a0 Corentin Chary
2340 999342a0 Corentin Chary
            rect->freq = res.tv_sec + res.tv_usec / 1000000.;
2341 999342a0 Corentin Chary
            rect->freq /= count;
2342 999342a0 Corentin Chary
            rect->freq = 1. / rect->freq;
2343 999342a0 Corentin Chary
        }
2344 999342a0 Corentin Chary
    }
2345 7d964c9d Corentin Chary
    return has_dirty;
2346 999342a0 Corentin Chary
}
2347 999342a0 Corentin Chary
2348 999342a0 Corentin Chary
double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
2349 999342a0 Corentin Chary
{
2350 999342a0 Corentin Chary
    int i, j;
2351 999342a0 Corentin Chary
    double total = 0;
2352 999342a0 Corentin Chary
    int num = 0;
2353 999342a0 Corentin Chary
2354 999342a0 Corentin Chary
    x =  (x / VNC_STAT_RECT) * VNC_STAT_RECT;
2355 999342a0 Corentin Chary
    y =  (y / VNC_STAT_RECT) * VNC_STAT_RECT;
2356 999342a0 Corentin Chary
2357 999342a0 Corentin Chary
    for (j = y; j <= y + h; j += VNC_STAT_RECT) {
2358 999342a0 Corentin Chary
        for (i = x; i <= x + w; i += VNC_STAT_RECT) {
2359 999342a0 Corentin Chary
            total += vnc_stat_rect(vs->vd, i, j)->freq;
2360 999342a0 Corentin Chary
            num++;
2361 999342a0 Corentin Chary
        }
2362 999342a0 Corentin Chary
    }
2363 999342a0 Corentin Chary
2364 999342a0 Corentin Chary
    if (num) {
2365 999342a0 Corentin Chary
        return total / num;
2366 999342a0 Corentin Chary
    } else {
2367 999342a0 Corentin Chary
        return 0;
2368 999342a0 Corentin Chary
    }
2369 999342a0 Corentin Chary
}
2370 999342a0 Corentin Chary
2371 999342a0 Corentin Chary
static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
2372 999342a0 Corentin Chary
{
2373 999342a0 Corentin Chary
    VncRectStat *rect;
2374 999342a0 Corentin Chary
2375 999342a0 Corentin Chary
    rect = vnc_stat_rect(vd, x, y);
2376 999342a0 Corentin Chary
    if (rect->updated) {
2377 999342a0 Corentin Chary
        return ;
2378 999342a0 Corentin Chary
    }
2379 999342a0 Corentin Chary
    rect->times[rect->idx] = *tv;
2380 999342a0 Corentin Chary
    rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times);
2381 999342a0 Corentin Chary
    rect->updated = true;
2382 999342a0 Corentin Chary
}
2383 999342a0 Corentin Chary
2384 1fc62412 Stefano Stabellini
static int vnc_refresh_server_surface(VncDisplay *vd)
2385 1fc62412 Stefano Stabellini
{
2386 1fc62412 Stefano Stabellini
    int y;
2387 1fc62412 Stefano Stabellini
    uint8_t *guest_row;
2388 1fc62412 Stefano Stabellini
    uint8_t *server_row;
2389 1fc62412 Stefano Stabellini
    int cmp_bytes;
2390 41b4bef6 Amit Shah
    VncState *vs;
2391 1fc62412 Stefano Stabellini
    int has_dirty = 0;
2392 1fc62412 Stefano Stabellini
2393 80e0c8c3 Corentin Chary
    struct timeval tv = { 0, 0 };
2394 999342a0 Corentin Chary
2395 80e0c8c3 Corentin Chary
    if (!vd->non_adaptive) {
2396 80e0c8c3 Corentin Chary
        gettimeofday(&tv, NULL);
2397 80e0c8c3 Corentin Chary
        has_dirty = vnc_update_stats(vd, &tv);
2398 80e0c8c3 Corentin Chary
    }
2399 999342a0 Corentin Chary
2400 1fc62412 Stefano Stabellini
    /*
2401 1fc62412 Stefano Stabellini
     * Walk through the guest dirty map.
2402 1fc62412 Stefano Stabellini
     * Check and copy modified bits from guest to server surface.
2403 1fc62412 Stefano Stabellini
     * Update server dirty map.
2404 1fc62412 Stefano Stabellini
     */
2405 1fc62412 Stefano Stabellini
    cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
2406 1fc62412 Stefano Stabellini
    guest_row  = vd->guest.ds->data;
2407 1fc62412 Stefano Stabellini
    server_row = vd->server->data;
2408 1fc62412 Stefano Stabellini
    for (y = 0; y < vd->guest.ds->height; y++) {
2409 23bfe28f Stefan Weil
        if (!bitmap_empty(vd->guest.dirty[y], VNC_DIRTY_BITS)) {
2410 1fc62412 Stefano Stabellini
            int x;
2411 1fc62412 Stefano Stabellini
            uint8_t *guest_ptr;
2412 1fc62412 Stefano Stabellini
            uint8_t *server_ptr;
2413 1fc62412 Stefano Stabellini
2414 1fc62412 Stefano Stabellini
            guest_ptr  = guest_row;
2415 1fc62412 Stefano Stabellini
            server_ptr = server_row;
2416 1fc62412 Stefano Stabellini
2417 1fc62412 Stefano Stabellini
            for (x = 0; x < vd->guest.ds->width;
2418 1fc62412 Stefano Stabellini
                    x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
2419 bc2429b9 Corentin Chary
                if (!test_and_clear_bit((x / 16), vd->guest.dirty[y]))
2420 1fc62412 Stefano Stabellini
                    continue;
2421 1fc62412 Stefano Stabellini
                if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
2422 1fc62412 Stefano Stabellini
                    continue;
2423 1fc62412 Stefano Stabellini
                memcpy(server_ptr, guest_ptr, cmp_bytes);
2424 80e0c8c3 Corentin Chary
                if (!vd->non_adaptive)
2425 80e0c8c3 Corentin Chary
                    vnc_rect_updated(vd, x, y, &tv);
2426 41b4bef6 Amit Shah
                QTAILQ_FOREACH(vs, &vd->clients, next) {
2427 bc2429b9 Corentin Chary
                    set_bit((x / 16), vs->dirty[y]);
2428 1fc62412 Stefano Stabellini
                }
2429 1fc62412 Stefano Stabellini
                has_dirty++;
2430 1fc62412 Stefano Stabellini
            }
2431 1fc62412 Stefano Stabellini
        }
2432 1fc62412 Stefano Stabellini
        guest_row  += ds_get_linesize(vd->ds);
2433 1fc62412 Stefano Stabellini
        server_row += ds_get_linesize(vd->ds);
2434 1fc62412 Stefano Stabellini
    }
2435 1fc62412 Stefano Stabellini
    return has_dirty;
2436 1fc62412 Stefano Stabellini
}
2437 1fc62412 Stefano Stabellini
2438 703bc68f Stefano Stabellini
static void vnc_refresh(void *opaque)
2439 703bc68f Stefano Stabellini
{
2440 703bc68f Stefano Stabellini
    VncDisplay *vd = opaque;
2441 41b4bef6 Amit Shah
    VncState *vs, *vn;
2442 41b4bef6 Amit Shah
    int has_dirty, rects = 0;
2443 703bc68f Stefano Stabellini
2444 703bc68f Stefano Stabellini
    vga_hw_update();
2445 703bc68f Stefano Stabellini
2446 bd023f95 Corentin Chary
    if (vnc_trylock_display(vd)) {
2447 bd023f95 Corentin Chary
        vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
2448 7bd427d8 Paolo Bonzini
        qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) +
2449 bd023f95 Corentin Chary
                       vd->timer_interval);
2450 bd023f95 Corentin Chary
        return;
2451 bd023f95 Corentin Chary
    }
2452 bd023f95 Corentin Chary
2453 1fc62412 Stefano Stabellini
    has_dirty = vnc_refresh_server_surface(vd);
2454 bd023f95 Corentin Chary
    vnc_unlock_display(vd);
2455 1fc62412 Stefano Stabellini
2456 41b4bef6 Amit Shah
    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
2457 2430ffe4 Stefano Stabellini
        rects += vnc_update_client(vs, has_dirty);
2458 6185c578 Stefano Stabellini
        /* vs might be free()ed here */
2459 703bc68f Stefano Stabellini
    }
2460 bd023f95 Corentin Chary
2461 83755c17 Stefano Stabellini
    /* vd->timer could be NULL now if the last client disconnected,
2462 83755c17 Stefano Stabellini
     * in this case don't update the timer */
2463 83755c17 Stefano Stabellini
    if (vd->timer == NULL)
2464 83755c17 Stefano Stabellini
        return;
2465 703bc68f Stefano Stabellini
2466 2430ffe4 Stefano Stabellini
    if (has_dirty && rects) {
2467 2430ffe4 Stefano Stabellini
        vd->timer_interval /= 2;
2468 2430ffe4 Stefano Stabellini
        if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE)
2469 2430ffe4 Stefano Stabellini
            vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
2470 2430ffe4 Stefano Stabellini
    } else {
2471 2430ffe4 Stefano Stabellini
        vd->timer_interval += VNC_REFRESH_INTERVAL_INC;
2472 2430ffe4 Stefano Stabellini
        if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX)
2473 2430ffe4 Stefano Stabellini
            vd->timer_interval = VNC_REFRESH_INTERVAL_MAX;
2474 2430ffe4 Stefano Stabellini
    }
2475 7bd427d8 Paolo Bonzini
    qemu_mod_timer(vd->timer, qemu_get_clock_ms(rt_clock) + vd->timer_interval);
2476 703bc68f Stefano Stabellini
}
2477 703bc68f Stefano Stabellini
2478 703bc68f Stefano Stabellini
static void vnc_init_timer(VncDisplay *vd)
2479 703bc68f Stefano Stabellini
{
2480 2430ffe4 Stefano Stabellini
    vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
2481 41b4bef6 Amit Shah
    if (vd->timer == NULL && !QTAILQ_EMPTY(&vd->clients)) {
2482 7bd427d8 Paolo Bonzini
        vd->timer = qemu_new_timer_ms(rt_clock, vnc_refresh, vd);
2483 5db8378a Stefan Weil
        vnc_dpy_resize(vd->ds);
2484 1fc62412 Stefano Stabellini
        vnc_refresh(vd);
2485 703bc68f Stefano Stabellini
    }
2486 703bc68f Stefano Stabellini
}
2487 703bc68f Stefano Stabellini
2488 703bc68f Stefano Stabellini
static void vnc_remove_timer(VncDisplay *vd)
2489 703bc68f Stefano Stabellini
{
2490 41b4bef6 Amit Shah
    if (vd->timer != NULL && QTAILQ_EMPTY(&vd->clients)) {
2491 703bc68f Stefano Stabellini
        qemu_del_timer(vd->timer);
2492 703bc68f Stefano Stabellini
        qemu_free_timer(vd->timer);
2493 703bc68f Stefano Stabellini
        vd->timer = NULL;
2494 703bc68f Stefano Stabellini
    }
2495 703bc68f Stefano Stabellini
}
2496 703bc68f Stefano Stabellini
2497 753b4053 aliguori
static void vnc_connect(VncDisplay *vd, int csock)
2498 3aa3eea3 balrog
{
2499 753b4053 aliguori
    VncState *vs = qemu_mallocz(sizeof(VncState));
2500 7d964c9d Corentin Chary
    int i;
2501 7d964c9d Corentin Chary
2502 753b4053 aliguori
    vs->csock = csock;
2503 7d964c9d Corentin Chary
    vs->lossy_rect = qemu_mallocz(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
2504 7d964c9d Corentin Chary
    for (i = 0; i < VNC_STAT_ROWS; ++i) {
2505 7d964c9d Corentin Chary
        vs->lossy_rect[i] = qemu_mallocz(VNC_STAT_COLS * sizeof (uint8_t));
2506 7d964c9d Corentin Chary
    }
2507 753b4053 aliguori
2508 753b4053 aliguori
    VNC_DEBUG("New client on socket %d\n", csock);
2509 7d957bd8 aliguori
    dcl->idle = 0;
2510 3aa3eea3 balrog
    socket_set_nonblock(vs->csock);
2511 3aa3eea3 balrog
    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
2512 753b4053 aliguori
2513 4a80dba3 Luiz Capitulino
    vnc_client_cache_addr(vs);
2514 586153d9 Luiz Capitulino
    vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
2515 4a80dba3 Luiz Capitulino
2516 753b4053 aliguori
    vs->vd = vd;
2517 753b4053 aliguori
    vs->ds = vd->ds;
2518 753b4053 aliguori
    vs->last_x = -1;
2519 753b4053 aliguori
    vs->last_y = -1;
2520 753b4053 aliguori
2521 753b4053 aliguori
    vs->as.freq = 44100;
2522 753b4053 aliguori
    vs->as.nchannels = 2;
2523 753b4053 aliguori
    vs->as.fmt = AUD_FMT_S16;
2524 753b4053 aliguori
    vs->as.endianness = 0;
2525 753b4053 aliguori
2526 bd023f95 Corentin Chary
#ifdef CONFIG_VNC_THREAD
2527 bd023f95 Corentin Chary
    qemu_mutex_init(&vs->output_mutex);
2528 bd023f95 Corentin Chary
#endif
2529 bd023f95 Corentin Chary
2530 41b4bef6 Amit Shah
    QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
2531 1fc62412 Stefano Stabellini
2532 1fc62412 Stefano Stabellini
    vga_hw_update();
2533 1fc62412 Stefano Stabellini
2534 3aa3eea3 balrog
    vnc_write(vs, "RFB 003.008\n", 12);
2535 3aa3eea3 balrog
    vnc_flush(vs);
2536 3aa3eea3 balrog
    vnc_read_when(vs, protocol_version, 12);
2537 53762ddb malc
    reset_keys(vs);
2538 3a0558b5 Gerd Hoffmann
    if (vs->vd->lock_key_sync)
2539 3a0558b5 Gerd Hoffmann
        vs->led = qemu_add_led_event_handler(kbd_leds, vs);
2540 753b4053 aliguori
2541 37c34d9d Anthony Liguori
    vs->mouse_mode_notifier.notify = check_pointer_type_change;
2542 37c34d9d Anthony Liguori
    qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
2543 37c34d9d Anthony Liguori
2544 703bc68f Stefano Stabellini
    vnc_init_timer(vd);
2545 1fc62412 Stefano Stabellini
2546 198a0039 Gerd Hoffmann
    /* vs might be free()ed here */
2547 3aa3eea3 balrog
}
2548 3aa3eea3 balrog
2549 24236869 bellard
static void vnc_listen_read(void *opaque)
2550 24236869 bellard
{
2551 753b4053 aliguori
    VncDisplay *vs = opaque;
2552 24236869 bellard
    struct sockaddr_in addr;
2553 24236869 bellard
    socklen_t addrlen = sizeof(addr);
2554 24236869 bellard
2555 9f60ad50 balrog
    /* Catch-up */
2556 9f60ad50 balrog
    vga_hw_update();
2557 9f60ad50 balrog
2558 40ff6d7e Kevin Wolf
    int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
2559 753b4053 aliguori
    if (csock != -1) {
2560 753b4053 aliguori
        vnc_connect(vs, csock);
2561 24236869 bellard
    }
2562 24236869 bellard
}
2563 24236869 bellard
2564 71cab5ca ths
void vnc_display_init(DisplayState *ds)
2565 24236869 bellard
{
2566 afd32160 Stefan Weil
    VncDisplay *vs = qemu_mallocz(sizeof(*vs));
2567 24236869 bellard
2568 7d957bd8 aliguori
    dcl = qemu_mallocz(sizeof(DisplayChangeListener));
2569 24236869 bellard
2570 24236869 bellard
    ds->opaque = vs;
2571 7d957bd8 aliguori
    dcl->idle = 1;
2572 753b4053 aliguori
    vnc_display = vs;
2573 24236869 bellard
2574 24236869 bellard
    vs->lsock = -1;
2575 24236869 bellard
2576 24236869 bellard
    vs->ds = ds;
2577 41b4bef6 Amit Shah
    QTAILQ_INIT(&vs->clients);
2578 3c9405a0 Gerd Hoffmann
    vs->expires = TIME_MAX;
2579 24236869 bellard
2580 9ca313aa aliguori
    if (keyboard_layout)
2581 0483755a aliguori
        vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
2582 9ca313aa aliguori
    else
2583 0483755a aliguori
        vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
2584 24236869 bellard
2585 24236869 bellard
    if (!vs->kbd_layout)
2586 28a76be8 aliguori
        exit(1);
2587 24236869 bellard
2588 bd023f95 Corentin Chary
#ifdef CONFIG_VNC_THREAD
2589 bd023f95 Corentin Chary
    qemu_mutex_init(&vs->mutex);
2590 bd023f95 Corentin Chary
    vnc_start_worker_thread();
2591 bd023f95 Corentin Chary
#endif
2592 bd023f95 Corentin Chary
2593 753b4053 aliguori
    dcl->dpy_copy = vnc_dpy_copy;
2594 7d957bd8 aliguori
    dcl->dpy_update = vnc_dpy_update;
2595 7d957bd8 aliguori
    dcl->dpy_resize = vnc_dpy_resize;
2596 7d957bd8 aliguori
    dcl->dpy_setdata = vnc_dpy_setdata;
2597 7d957bd8 aliguori
    register_displaychangelistener(ds, dcl);
2598 d467b679 Gerd Hoffmann
    ds->mouse_set = vnc_mouse_set;
2599 d467b679 Gerd Hoffmann
    ds->cursor_define = vnc_dpy_cursor_define;
2600 71cab5ca ths
}
2601 71cab5ca ths
2602 6f43024c ths
2603 71cab5ca ths
void vnc_display_close(DisplayState *ds)
2604 71cab5ca ths
{
2605 753b4053 aliguori
    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
2606 71cab5ca ths
2607 452b4d88 aliguori
    if (!vs)
2608 452b4d88 aliguori
        return;
2609 71cab5ca ths
    if (vs->display) {
2610 28a76be8 aliguori
        qemu_free(vs->display);
2611 28a76be8 aliguori
        vs->display = NULL;
2612 71cab5ca ths
    }
2613 71cab5ca ths
    if (vs->lsock != -1) {
2614 28a76be8 aliguori
        qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
2615 28a76be8 aliguori
        close(vs->lsock);
2616 28a76be8 aliguori
        vs->lsock = -1;
2617 71cab5ca ths
    }
2618 70848515 ths
    vs->auth = VNC_AUTH_INVALID;
2619 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
2620 8d5d2d4c ths
    vs->subauth = VNC_AUTH_INVALID;
2621 5fb6c7a8 aliguori
    vs->tls.x509verify = 0;
2622 8d5d2d4c ths
#endif
2623 70848515 ths
}
2624 70848515 ths
2625 1cd20f8b Anthony Liguori
int vnc_display_disable_login(DisplayState *ds)
2626 1cd20f8b Anthony Liguori
{
2627 1cd20f8b Anthony Liguori
    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
2628 1cd20f8b Anthony Liguori
2629 1cd20f8b Anthony Liguori
    if (!vs) {
2630 1cd20f8b Anthony Liguori
        return -1;
2631 1cd20f8b Anthony Liguori
    }
2632 1cd20f8b Anthony Liguori
2633 1cd20f8b Anthony Liguori
    if (vs->password) {
2634 1cd20f8b Anthony Liguori
        qemu_free(vs->password);
2635 1cd20f8b Anthony Liguori
    }
2636 1cd20f8b Anthony Liguori
2637 1cd20f8b Anthony Liguori
    vs->password = NULL;
2638 1cd20f8b Anthony Liguori
    vs->auth = VNC_AUTH_VNC;
2639 1cd20f8b Anthony Liguori
2640 1cd20f8b Anthony Liguori
    return 0;
2641 1cd20f8b Anthony Liguori
}
2642 1cd20f8b Anthony Liguori
2643 70848515 ths
int vnc_display_password(DisplayState *ds, const char *password)
2644 70848515 ths
{
2645 821601ea Jes Sorensen
    int ret = 0;
2646 753b4053 aliguori
    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
2647 70848515 ths
2648 7ef92331 Zachary Amsden
    if (!vs) {
2649 821601ea Jes Sorensen
        ret = -EINVAL;
2650 821601ea Jes Sorensen
        goto out;
2651 7ef92331 Zachary Amsden
    }
2652 7ef92331 Zachary Amsden
2653 1cd20f8b Anthony Liguori
    if (!password) {
2654 1cd20f8b Anthony Liguori
        /* This is not the intention of this interface but err on the side
2655 1cd20f8b Anthony Liguori
           of being safe */
2656 821601ea Jes Sorensen
        ret = vnc_display_disable_login(ds);
2657 821601ea Jes Sorensen
        goto out;
2658 1cd20f8b Anthony Liguori
    }
2659 1cd20f8b Anthony Liguori
2660 70848515 ths
    if (vs->password) {
2661 28a76be8 aliguori
        qemu_free(vs->password);
2662 28a76be8 aliguori
        vs->password = NULL;
2663 70848515 ths
    }
2664 1cd20f8b Anthony Liguori
    vs->password = qemu_strdup(password);
2665 1cd20f8b Anthony Liguori
    vs->auth = VNC_AUTH_VNC;
2666 821601ea Jes Sorensen
out:
2667 821601ea Jes Sorensen
    if (ret != 0) {
2668 821601ea Jes Sorensen
        qerror_report(QERR_SET_PASSWD_FAILED);
2669 821601ea Jes Sorensen
    }
2670 821601ea Jes Sorensen
    return ret;
2671 71cab5ca ths
}
2672 71cab5ca ths
2673 3c9405a0 Gerd Hoffmann
int vnc_display_pw_expire(DisplayState *ds, time_t expires)
2674 3c9405a0 Gerd Hoffmann
{
2675 3c9405a0 Gerd Hoffmann
    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
2676 3c9405a0 Gerd Hoffmann
2677 3c9405a0 Gerd Hoffmann
    vs->expires = expires;
2678 3c9405a0 Gerd Hoffmann
    return 0;
2679 3c9405a0 Gerd Hoffmann
}
2680 3c9405a0 Gerd Hoffmann
2681 f92f8afe Anthony Liguori
char *vnc_display_local_addr(DisplayState *ds)
2682 f92f8afe Anthony Liguori
{
2683 f92f8afe Anthony Liguori
    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
2684 f92f8afe Anthony Liguori
    
2685 f92f8afe Anthony Liguori
    return vnc_socket_local_addr("%s:%s", vs->lsock);
2686 f92f8afe Anthony Liguori
}
2687 f92f8afe Anthony Liguori
2688 70848515 ths
int vnc_display_open(DisplayState *ds, const char *display)
2689 71cab5ca ths
{
2690 753b4053 aliguori
    VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
2691 70848515 ths
    const char *options;
2692 70848515 ths
    int password = 0;
2693 3aa3eea3 balrog
    int reverse = 0;
2694 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
2695 3a702699 ths
    int tls = 0, x509 = 0;
2696 8d5d2d4c ths
#endif
2697 2f9606b3 aliguori
#ifdef CONFIG_VNC_SASL
2698 2f9606b3 aliguori
    int sasl = 0;
2699 2f9606b3 aliguori
    int saslErr;
2700 2f9606b3 aliguori
#endif
2701 2ded6ad7 Blue Swirl
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
2702 76655d6d aliguori
    int acl = 0;
2703 2ded6ad7 Blue Swirl
#endif
2704 3a0558b5 Gerd Hoffmann
    int lock_key_sync = 1;
2705 71cab5ca ths
2706 753b4053 aliguori
    if (!vnc_display)
2707 452b4d88 aliguori
        return -1;
2708 71cab5ca ths
    vnc_display_close(ds);
2709 70848515 ths
    if (strcmp(display, "none") == 0)
2710 28a76be8 aliguori
        return 0;
2711 24236869 bellard
2712 70848515 ths
    if (!(vs->display = strdup(display)))
2713 28a76be8 aliguori
        return -1;
2714 70848515 ths
2715 70848515 ths
    options = display;
2716 70848515 ths
    while ((options = strchr(options, ','))) {
2717 28a76be8 aliguori
        options++;
2718 28a76be8 aliguori
        if (strncmp(options, "password", 8) == 0) {
2719 28a76be8 aliguori
            password = 1; /* Require password auth */
2720 28a76be8 aliguori
        } else if (strncmp(options, "reverse", 7) == 0) {
2721 28a76be8 aliguori
            reverse = 1;
2722 3a0558b5 Gerd Hoffmann
        } else if (strncmp(options, "no-lock-key-sync", 9) == 0) {
2723 3a0558b5 Gerd Hoffmann
            lock_key_sync = 0;
2724 2f9606b3 aliguori
#ifdef CONFIG_VNC_SASL
2725 28a76be8 aliguori
        } else if (strncmp(options, "sasl", 4) == 0) {
2726 28a76be8 aliguori
            sasl = 1; /* Require SASL auth */
2727 2f9606b3 aliguori
#endif
2728 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
2729 28a76be8 aliguori
        } else if (strncmp(options, "tls", 3) == 0) {
2730 28a76be8 aliguori
            tls = 1; /* Require TLS */
2731 28a76be8 aliguori
        } else if (strncmp(options, "x509", 4) == 0) {
2732 28a76be8 aliguori
            char *start, *end;
2733 28a76be8 aliguori
            x509 = 1; /* Require x509 certificates */
2734 28a76be8 aliguori
            if (strncmp(options, "x509verify", 10) == 0)
2735 28a76be8 aliguori
                vs->tls.x509verify = 1; /* ...and verify client certs */
2736 28a76be8 aliguori
2737 28a76be8 aliguori
            /* Now check for 'x509=/some/path' postfix
2738 28a76be8 aliguori
             * and use that to setup x509 certificate/key paths */
2739 28a76be8 aliguori
            start = strchr(options, '=');
2740 28a76be8 aliguori
            end = strchr(options, ',');
2741 28a76be8 aliguori
            if (start && (!end || (start < end))) {
2742 28a76be8 aliguori
                int len = end ? end-(start+1) : strlen(start+1);
2743 28a76be8 aliguori
                char *path = qemu_strndup(start + 1, len);
2744 28a76be8 aliguori
2745 28a76be8 aliguori
                VNC_DEBUG("Trying certificate path '%s'\n", path);
2746 28a76be8 aliguori
                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
2747 28a76be8 aliguori
                    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
2748 28a76be8 aliguori
                    qemu_free(path);
2749 28a76be8 aliguori
                    qemu_free(vs->display);
2750 28a76be8 aliguori
                    vs->display = NULL;
2751 28a76be8 aliguori
                    return -1;
2752 28a76be8 aliguori
                }
2753 28a76be8 aliguori
                qemu_free(path);
2754 28a76be8 aliguori
            } else {
2755 28a76be8 aliguori
                fprintf(stderr, "No certificate path provided\n");
2756 28a76be8 aliguori
                qemu_free(vs->display);
2757 28a76be8 aliguori
                vs->display = NULL;
2758 28a76be8 aliguori
                return -1;
2759 28a76be8 aliguori
            }
2760 8d5d2d4c ths
#endif
2761 2ded6ad7 Blue Swirl
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
2762 28a76be8 aliguori
        } else if (strncmp(options, "acl", 3) == 0) {
2763 28a76be8 aliguori
            acl = 1;
2764 2ded6ad7 Blue Swirl
#endif
2765 6f9c78c1 Corentin Chary
        } else if (strncmp(options, "lossy", 5) == 0) {
2766 6f9c78c1 Corentin Chary
            vs->lossy = true;
2767 80e0c8c3 Corentin Chary
        } else if (strncmp(options, "non-adapative", 13) == 0) {
2768 80e0c8c3 Corentin Chary
            vs->non_adaptive = true;
2769 28a76be8 aliguori
        }
2770 70848515 ths
    }
2771 70848515 ths
2772 76655d6d aliguori
#ifdef CONFIG_VNC_TLS
2773 76655d6d aliguori
    if (acl && x509 && vs->tls.x509verify) {
2774 28a76be8 aliguori
        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
2775 28a76be8 aliguori
            fprintf(stderr, "Failed to create x509 dname ACL\n");
2776 28a76be8 aliguori
            exit(1);
2777 28a76be8 aliguori
        }
2778 76655d6d aliguori
    }
2779 76655d6d aliguori
#endif
2780 76655d6d aliguori
#ifdef CONFIG_VNC_SASL
2781 76655d6d aliguori
    if (acl && sasl) {
2782 28a76be8 aliguori
        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
2783 28a76be8 aliguori
            fprintf(stderr, "Failed to create username ACL\n");
2784 28a76be8 aliguori
            exit(1);
2785 28a76be8 aliguori
        }
2786 76655d6d aliguori
    }
2787 76655d6d aliguori
#endif
2788 76655d6d aliguori
2789 2f9606b3 aliguori
    /*
2790 2f9606b3 aliguori
     * Combinations we support here:
2791 2f9606b3 aliguori
     *
2792 2f9606b3 aliguori
     *  - no-auth                (clear text, no auth)
2793 2f9606b3 aliguori
     *  - password               (clear text, weak auth)
2794 2f9606b3 aliguori
     *  - sasl                   (encrypt, good auth *IF* using Kerberos via GSSAPI)
2795 2f9606b3 aliguori
     *  - tls                    (encrypt, weak anonymous creds, no auth)
2796 2f9606b3 aliguori
     *  - tls + password         (encrypt, weak anonymous creds, weak auth)
2797 2f9606b3 aliguori
     *  - tls + sasl             (encrypt, weak anonymous creds, good auth)
2798 2f9606b3 aliguori
     *  - tls + x509             (encrypt, good x509 creds, no auth)
2799 2f9606b3 aliguori
     *  - tls + x509 + password  (encrypt, good x509 creds, weak auth)
2800 2f9606b3 aliguori
     *  - tls + x509 + sasl      (encrypt, good x509 creds, good auth)
2801 2f9606b3 aliguori
     *
2802 2f9606b3 aliguori
     * NB1. TLS is a stackable auth scheme.
2803 2f9606b3 aliguori
     * NB2. the x509 schemes have option to validate a client cert dname
2804 2f9606b3 aliguori
     */
2805 70848515 ths
    if (password) {
2806 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
2807 28a76be8 aliguori
        if (tls) {
2808 28a76be8 aliguori
            vs->auth = VNC_AUTH_VENCRYPT;
2809 28a76be8 aliguori
            if (x509) {
2810 28a76be8 aliguori
                VNC_DEBUG("Initializing VNC server with x509 password auth\n");
2811 28a76be8 aliguori
                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
2812 28a76be8 aliguori
            } else {
2813 28a76be8 aliguori
                VNC_DEBUG("Initializing VNC server with TLS password auth\n");
2814 28a76be8 aliguori
                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
2815 28a76be8 aliguori
            }
2816 28a76be8 aliguori
        } else {
2817 2f9606b3 aliguori
#endif /* CONFIG_VNC_TLS */
2818 28a76be8 aliguori
            VNC_DEBUG("Initializing VNC server with password auth\n");
2819 28a76be8 aliguori
            vs->auth = VNC_AUTH_VNC;
2820 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
2821 28a76be8 aliguori
            vs->subauth = VNC_AUTH_INVALID;
2822 28a76be8 aliguori
        }
2823 2f9606b3 aliguori
#endif /* CONFIG_VNC_TLS */
2824 2f9606b3 aliguori
#ifdef CONFIG_VNC_SASL
2825 2f9606b3 aliguori
    } else if (sasl) {
2826 2f9606b3 aliguori
#ifdef CONFIG_VNC_TLS
2827 2f9606b3 aliguori
        if (tls) {
2828 2f9606b3 aliguori
            vs->auth = VNC_AUTH_VENCRYPT;
2829 2f9606b3 aliguori
            if (x509) {
2830 28a76be8 aliguori
                VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
2831 2f9606b3 aliguori
                vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
2832 2f9606b3 aliguori
            } else {
2833 28a76be8 aliguori
                VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
2834 2f9606b3 aliguori
                vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
2835 2f9606b3 aliguori
            }
2836 2f9606b3 aliguori
        } else {
2837 2f9606b3 aliguori
#endif /* CONFIG_VNC_TLS */
2838 28a76be8 aliguori
            VNC_DEBUG("Initializing VNC server with SASL auth\n");
2839 2f9606b3 aliguori
            vs->auth = VNC_AUTH_SASL;
2840 2f9606b3 aliguori
#ifdef CONFIG_VNC_TLS
2841 2f9606b3 aliguori
            vs->subauth = VNC_AUTH_INVALID;
2842 2f9606b3 aliguori
        }
2843 2f9606b3 aliguori
#endif /* CONFIG_VNC_TLS */
2844 2f9606b3 aliguori
#endif /* CONFIG_VNC_SASL */
2845 70848515 ths
    } else {
2846 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
2847 28a76be8 aliguori
        if (tls) {
2848 28a76be8 aliguori
            vs->auth = VNC_AUTH_VENCRYPT;
2849 28a76be8 aliguori
            if (x509) {
2850 28a76be8 aliguori
                VNC_DEBUG("Initializing VNC server with x509 no auth\n");
2851 28a76be8 aliguori
                vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
2852 28a76be8 aliguori
            } else {
2853 28a76be8 aliguori
                VNC_DEBUG("Initializing VNC server with TLS no auth\n");
2854 28a76be8 aliguori
                vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
2855 28a76be8 aliguori
            }
2856 28a76be8 aliguori
        } else {
2857 8d5d2d4c ths
#endif
2858 28a76be8 aliguori
            VNC_DEBUG("Initializing VNC server with no auth\n");
2859 28a76be8 aliguori
            vs->auth = VNC_AUTH_NONE;
2860 eb38c52c blueswir1
#ifdef CONFIG_VNC_TLS
2861 28a76be8 aliguori
            vs->subauth = VNC_AUTH_INVALID;
2862 28a76be8 aliguori
        }
2863 8d5d2d4c ths
#endif
2864 70848515 ths
    }
2865 24236869 bellard
2866 2f9606b3 aliguori
#ifdef CONFIG_VNC_SASL
2867 2f9606b3 aliguori
    if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
2868 2f9606b3 aliguori
        fprintf(stderr, "Failed to initialize SASL auth %s",
2869 2f9606b3 aliguori
                sasl_errstring(saslErr, NULL, NULL));
2870 2f9606b3 aliguori
        free(vs->display);
2871 2f9606b3 aliguori
        vs->display = NULL;
2872 2f9606b3 aliguori
        return -1;
2873 2f9606b3 aliguori
    }
2874 2f9606b3 aliguori
#endif
2875 3a0558b5 Gerd Hoffmann
    vs->lock_key_sync = lock_key_sync;
2876 2f9606b3 aliguori
2877 3aa3eea3 balrog
    if (reverse) {
2878 9712ecaf aliguori
        /* connect to viewer */
2879 9712ecaf aliguori
        if (strncmp(display, "unix:", 5) == 0)
2880 9712ecaf aliguori
            vs->lsock = unix_connect(display+5);
2881 9712ecaf aliguori
        else
2882 9712ecaf aliguori
            vs->lsock = inet_connect(display, SOCK_STREAM);
2883 9712ecaf aliguori
        if (-1 == vs->lsock) {
2884 3aa3eea3 balrog
            free(vs->display);
2885 3aa3eea3 balrog
            vs->display = NULL;
2886 3aa3eea3 balrog
            return -1;
2887 3aa3eea3 balrog
        } else {
2888 753b4053 aliguori
            int csock = vs->lsock;
2889 3aa3eea3 balrog
            vs->lsock = -1;
2890 753b4053 aliguori
            vnc_connect(vs, csock);
2891 3aa3eea3 balrog
        }
2892 9712ecaf aliguori
        return 0;
2893 24236869 bellard
2894 9712ecaf aliguori
    } else {
2895 9712ecaf aliguori
        /* listen for connects */
2896 9712ecaf aliguori
        char *dpy;
2897 9712ecaf aliguori
        dpy = qemu_malloc(256);
2898 9712ecaf aliguori
        if (strncmp(display, "unix:", 5) == 0) {
2899 bc575e95 blueswir1
            pstrcpy(dpy, 256, "unix:");
2900 4a55bfdf aliguori
            vs->lsock = unix_listen(display+5, dpy+5, 256-5);
2901 9712ecaf aliguori
        } else {
2902 9712ecaf aliguori
            vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900);
2903 9712ecaf aliguori
        }
2904 9712ecaf aliguori
        if (-1 == vs->lsock) {
2905 9712ecaf aliguori
            free(dpy);
2906 d0513623 balrog
            return -1;
2907 9712ecaf aliguori
        } else {
2908 9712ecaf aliguori
            free(vs->display);
2909 9712ecaf aliguori
            vs->display = dpy;
2910 9712ecaf aliguori
        }
2911 24236869 bellard
    }
2912 753b4053 aliguori
    return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
2913 24236869 bellard
}