blob: 9e3503d93d800f129ff5ae73c08e95d34a0877ab [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 }
Philippe Mathieu-Daudé7d5b0d62023-06-01 11:34:52 +020043 vs->ioc_tag = qio_channel_add_watch(vs->ioc,
44 G_IO_IN | G_IO_HUP | G_IO_ERR,
45 vncws_handshake_io, vs, NULL);
Tim Hardeck0057a0d2013-04-23 16:33:01 +020046 }
Tim Hardeck0057a0d2013-04-23 16:33:01 +020047}
48
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000049
Daniel P. Berrange04d25292015-02-27 16:20:57 +000050gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
Ding Hui2ddafce2020-10-29 11:22:41 +080051 GIOCondition condition,
Daniel P. Berrange04d25292015-02-27 16:20:57 +000052 void *opaque)
Tim Hardeck0057a0d2013-04-23 16:33:01 +020053{
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000054 VncState *vs = opaque;
55 QIOChannelTLS *tls;
Daniel P. Berrange3e305e42015-08-06 14:39:32 +010056 Error *err = NULL;
Tim Hardeck0057a0d2013-04-23 16:33:01 +020057
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000058 if (vs->ioc_tag) {
59 g_source_remove(vs->ioc_tag);
60 vs->ioc_tag = 0;
61 }
62
Ding Hui2ddafce2020-10-29 11:22:41 +080063 if (condition & (G_IO_HUP | G_IO_ERR)) {
64 vnc_client_error(vs);
65 return TRUE;
66 }
67
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000068 tls = qio_channel_tls_new_server(
69 vs->ioc,
70 vs->vd->tlscreds,
Daniel P. Berrangeb76806d2016-02-18 18:40:24 +000071 vs->vd->tlsauthzid,
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000072 &err);
73 if (!tls) {
74 VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
Daniel P. Berrange3e305e42015-08-06 14:39:32 +010075 error_free(err);
76 vnc_client_error(vs);
Daniel P. Berrange04d25292015-02-27 16:20:57 +000077 return TRUE;
Daniel P. Berrange51941e42015-03-17 13:42:58 +000078 }
Daniel P. Berrange3e305e42015-08-06 14:39:32 +010079
Daniel P. Berrange10bcfe52016-09-30 11:57:14 +010080 qio_channel_set_name(QIO_CHANNEL(tls), "vnc-ws-server-tls");
81
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000082 object_unref(OBJECT(vs->ioc));
83 vs->ioc = QIO_CHANNEL(tls);
Daniel P. Berrangead6374c2017-09-21 13:15:27 +010084 trace_vnc_client_io_wrap(vs, vs->ioc, "tls");
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000085 vs->tls = qio_channel_tls_get_session(tls);
86
87 qio_channel_tls_handshake(tls,
88 vncws_tls_handshake_done,
89 vs,
Peter Xu1939ccd2018-03-05 14:43:24 +080090 NULL,
Daniel P. Berrange2cc45222015-03-02 19:01:05 +000091 NULL);
92
Daniel P. Berrange04d25292015-02-27 16:20:57 +000093 return TRUE;
Tim Hardeck0057a0d2013-04-23 16:33:01 +020094}
Tim Hardeck0057a0d2013-04-23 16:33:01 +020095
Daniel P. Berranged5f04222015-03-11 15:53:49 +000096
Daniel P. Berrange60e705c2016-08-11 15:20:58 +010097static void vncws_handshake_done(QIOTask *task,
Daniel P. Berranged5f04222015-03-11 15:53:49 +000098 gpointer user_data)
Tim Hardeck7536ee42013-01-21 11:04:44 +010099{
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000100 VncState *vs = user_data;
Daniel P. Berrange60e705c2016-08-11 15:20:58 +0100101 Error *err = NULL;
Tim Hardeck7536ee42013-01-21 11:04:44 +0100102
Daniel P. Berrange60e705c2016-08-11 15:20:58 +0100103 if (qio_task_propagate_error(task, &err)) {
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000104 VNC_DEBUG("Websock handshake failed %s\n", error_get_pretty(err));
105 vnc_client_error(vs);
Daniel P. Berrange60e705c2016-08-11 15:20:58 +0100106 error_free(err);
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000107 } else {
108 VNC_DEBUG("Websock handshake complete, starting VNC protocol\n");
Daniel P. Berrangedbee9892016-09-29 16:45:40 +0100109 vnc_start_protocol(vs);
Brandon Carpentera75d6f02017-09-12 08:21:47 -0700110 if (vs->ioc_tag) {
111 g_source_remove(vs->ioc_tag);
112 }
Daniel P. Berrange04d25292015-02-27 16:20:57 +0000113 vs->ioc_tag = qio_channel_add_watch(
Ding Hui2ddafce2020-10-29 11:22:41 +0800114 vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR,
115 vnc_client_io, vs, NULL);
Tim Hardeck7536ee42013-01-21 11:04:44 +0100116 }
117}
118
119
Daniel P. Berrange04d25292015-02-27 16:20:57 +0000120gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
Ding Hui2ddafce2020-10-29 11:22:41 +0800121 GIOCondition condition,
Daniel P. Berrange04d25292015-02-27 16:20:57 +0000122 void *opaque)
123{
124 VncState *vs = opaque;
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000125 QIOChannelWebsock *wioc;
126
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000127 if (vs->ioc_tag) {
128 g_source_remove(vs->ioc_tag);
129 vs->ioc_tag = 0;
130 }
131
Ding Hui2ddafce2020-10-29 11:22:41 +0800132 if (condition & (G_IO_HUP | G_IO_ERR)) {
133 vnc_client_error(vs);
134 return TRUE;
135 }
136
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000137 wioc = qio_channel_websock_new_server(vs->ioc);
Daniel P. Berrange10bcfe52016-09-30 11:57:14 +0100138 qio_channel_set_name(QIO_CHANNEL(wioc), "vnc-ws-server-websock");
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000139
140 object_unref(OBJECT(vs->ioc));
141 vs->ioc = QIO_CHANNEL(wioc);
Daniel P. Berrangead6374c2017-09-21 13:15:27 +0100142 trace_vnc_client_io_wrap(vs, vs->ioc, "websock");
Daniel P. Berranged5f04222015-03-11 15:53:49 +0000143
144 qio_channel_websock_handshake(wioc,
145 vncws_handshake_done,
146 vs,
147 NULL);
148
Daniel P. Berrange04d25292015-02-27 16:20:57 +0000149 return TRUE;
150}