blob: 95c9703c72401e7f84a742510bb37b173004f3a3 [file] [log] [blame]
Tim Hardeck7536ee42013-01-21 11:04:44 +01001/*
2 * QEMU VNC display driver: Websockets support
3 *
4 * Copyright (C) 2010 Joel Martin
5 * Copyright (C) 2012 Tim Hardeck
6 *
7 * This is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this software; if not, see <http://www.gnu.org/licenses/>.
19 */
20
Peter Maydelle16f4c82016-01-29 17:49:51 +000021#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010022#include "qapi/error.h"
Tim Hardeck7536ee42013-01-21 11:04:44 +010023#include "vnc.h"
Daniel P. Berranged5f04222015-03-11 15:53:49 +000024#include "io/channel-websock.h"
Paolo Bonzini58369e22016-03-15 17:22:36 +010025#include "qemu/bswap.h"
Daniel P. Berrangead6374c2017-09-21 13:15:27 +010026#include "trace.h"
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000027
Daniel P. Berrange60e705c2016-08-11 15:20:58 +010028static void vncws_tls_handshake_done(QIOTask *task,
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000029 gpointer user_data)
Tim Hardeck0057a0d2013-04-23 16:33:01 +020030{
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000031 VncState *vs = user_data;
Daniel P. Berrange60e705c2016-08-11 15:20:58 +010032 Error *err = NULL;
Tim Hardeck0057a0d2013-04-23 16:33:01 +020033
Daniel P. Berrange60e705c2016-08-11 15:20:58 +010034 if (qio_task_propagate_error(task, &err)) {
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000035 VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
36 vnc_client_error(vs);
Daniel P. Berrange60e705c2016-08-11 15:20:58 +010037 error_free(err);
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000038 } else {
Daniel P. Berranged5f04222015-03-11 15:53:49 +000039 VNC_DEBUG("TLS handshake complete, starting websocket handshake\n");
Brandon Carpentera75d6f02017-09-12 08:21:47 -070040 if (vs->ioc_tag) {
41 g_source_remove(vs->ioc_tag);
42 }
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000043 vs->ioc_tag = qio_channel_add_watch(
44 QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL);
Tim Hardeck0057a0d2013-04-23 16:33:01 +020045 }
Tim Hardeck0057a0d2013-04-23 16:33:01 +020046}
47
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000048
Daniel P. Berrange04d25292015-02-27 16:20:57 +000049gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
50 GIOCondition condition G_GNUC_UNUSED,
51 void *opaque)
Tim Hardeck0057a0d2013-04-23 16:33:01 +020052{
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000053 VncState *vs = opaque;
54 QIOChannelTLS *tls;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +010055 Error *err = NULL;
Tim Hardeck0057a0d2013-04-23 16:33:01 +020056
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000057 if (vs->ioc_tag) {
58 g_source_remove(vs->ioc_tag);
59 vs->ioc_tag = 0;
60 }
61
62 tls = qio_channel_tls_new_server(
63 vs->ioc,
64 vs->vd->tlscreds,
Daniel P. Berrangeb76806d2016-02-18 18:40:24 +000065 vs->vd->tlsauthzid,
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000066 &err);
67 if (!tls) {
68 VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
Daniel P. Berrange3e305e42015-08-06 14:39:32 +010069 error_free(err);
70 vnc_client_error(vs);
Daniel P. Berrange04d25292015-02-27 16:20:57 +000071 return TRUE;
Daniel P. Berrange51941e42015-03-17 13:42:58 +000072 }
Daniel P. Berrange3e305e42015-08-06 14:39:32 +010073
Daniel P. Berrange10bcfe52016-09-30 11:57:14 +010074 qio_channel_set_name(QIO_CHANNEL(tls), "vnc-ws-server-tls");
75
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000076 object_unref(OBJECT(vs->ioc));
77 vs->ioc = QIO_CHANNEL(tls);
Daniel P. Berrangead6374c2017-09-21 13:15:27 +010078 trace_vnc_client_io_wrap(vs, vs->ioc, "tls");
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000079 vs->tls = qio_channel_tls_get_session(tls);
80
81 qio_channel_tls_handshake(tls,
82 vncws_tls_handshake_done,
83 vs,
Peter Xu1939ccd2018-03-05 14:43:24 +080084 NULL,
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000085 NULL);
86
Daniel P. Berrange04d25292015-02-27 16:20:57 +000087 return TRUE;
Tim Hardeck0057a0d2013-04-23 16:33:01 +020088}
Tim Hardeck0057a0d2013-04-23 16:33:01 +020089
Daniel P. Berranged5f04222015-03-11 15:53:49 +000090
Daniel P. Berrange60e705c2016-08-11 15:20:58 +010091static void vncws_handshake_done(QIOTask *task,
Daniel P. Berranged5f04222015-03-11 15:53:49 +000092 gpointer user_data)
Tim Hardeck7536ee42013-01-21 11:04:44 +010093{
Daniel P. Berranged5f04222015-03-11 15:53:49 +000094 VncState *vs = user_data;
Daniel P. Berrange60e705c2016-08-11 15:20:58 +010095 Error *err = NULL;
Tim Hardeck7536ee42013-01-21 11:04:44 +010096
Daniel P. Berrange60e705c2016-08-11 15:20:58 +010097 if (qio_task_propagate_error(task, &err)) {
Daniel P. Berranged5f04222015-03-11 15:53:49 +000098 VNC_DEBUG("Websock handshake failed %s\n", error_get_pretty(err));
99 vnc_client_error(vs);
Daniel P. Berrange60e705c2016-08-11 15:20:58 +0100100 error_free(err);
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000101 } else {
102 VNC_DEBUG("Websock handshake complete, starting VNC protocol\n");
Daniel P. Berrangedbee9892016-09-29 16:45:40 +0100103 vnc_start_protocol(vs);
Brandon Carpentera75d6f02017-09-12 08:21:47 -0700104 if (vs->ioc_tag) {
105 g_source_remove(vs->ioc_tag);
106 }
Daniel P. Berrange04d25292015-02-27 16:20:57 +0000107 vs->ioc_tag = qio_channel_add_watch(
108 vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
Tim Hardeck7536ee42013-01-21 11:04:44 +0100109 }
110}
111
112
Daniel P. Berrange04d25292015-02-27 16:20:57 +0000113gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
114 GIOCondition condition G_GNUC_UNUSED,
115 void *opaque)
116{
117 VncState *vs = opaque;
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000118 QIOChannelWebsock *wioc;
119
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000120 if (vs->ioc_tag) {
121 g_source_remove(vs->ioc_tag);
122 vs->ioc_tag = 0;
123 }
124
125 wioc = qio_channel_websock_new_server(vs->ioc);
Daniel P. Berrange10bcfe52016-09-30 11:57:14 +0100126 qio_channel_set_name(QIO_CHANNEL(wioc), "vnc-ws-server-websock");
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000127
128 object_unref(OBJECT(vs->ioc));
129 vs->ioc = QIO_CHANNEL(wioc);
Daniel P. Berrangead6374c2017-09-21 13:15:27 +0100130 trace_vnc_client_io_wrap(vs, vs->ioc, "websock");
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000131
132 qio_channel_websock_handshake(wioc,
133 vncws_handshake_done,
134 vs,
135 NULL);
136
Daniel P. Berrange04d25292015-02-27 16:20:57 +0000137 return TRUE;
138}