17536ee4bSTim Hardeck /* 27536ee4bSTim Hardeck * QEMU VNC display driver: Websockets support 37536ee4bSTim Hardeck * 47536ee4bSTim Hardeck * Copyright (C) 2010 Joel Martin 57536ee4bSTim Hardeck * Copyright (C) 2012 Tim Hardeck 67536ee4bSTim Hardeck * 77536ee4bSTim Hardeck * This is free software; you can redistribute it and/or modify 87536ee4bSTim Hardeck * it under the terms of the GNU General Public License as published by 97536ee4bSTim Hardeck * the Free Software Foundation; either version 2 of the License, or 107536ee4bSTim Hardeck * (at your option) any later version. 117536ee4bSTim Hardeck * 127536ee4bSTim Hardeck * This software is distributed in the hope that it will be useful, 137536ee4bSTim Hardeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 147536ee4bSTim Hardeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 157536ee4bSTim Hardeck * GNU General Public License for more details. 167536ee4bSTim Hardeck * 177536ee4bSTim Hardeck * You should have received a copy of the GNU General Public License 187536ee4bSTim Hardeck * along with this software; if not, see <http://www.gnu.org/licenses/>. 197536ee4bSTim Hardeck */ 207536ee4bSTim Hardeck 21e16f4c87SPeter Maydell #include "qemu/osdep.h" 22da34e65cSMarkus Armbruster #include "qapi/error.h" 237536ee4bSTim Hardeck #include "vnc.h" 24d5f04223SDaniel P. Berrange #include "io/channel-websock.h" 2558369e22SPaolo Bonzini #include "qemu/bswap.h" 26ad6374c4SDaniel P. Berrange #include "trace.h" 272cc45228SDaniel P. Berrange 2860e705c5SDaniel P. Berrange static void vncws_tls_handshake_done(QIOTask *task, 292cc45228SDaniel P. Berrange gpointer user_data) 300057a0d5STim Hardeck { 312cc45228SDaniel P. Berrange VncState *vs = user_data; 3260e705c5SDaniel P. Berrange Error *err = NULL; 330057a0d5STim Hardeck 3460e705c5SDaniel P. Berrange if (qio_task_propagate_error(task, &err)) { 353e305e4aSDaniel P. Berrange VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err)); 363e305e4aSDaniel P. Berrange vnc_client_error(vs); 3760e705c5SDaniel P. Berrange error_free(err); 382cc45228SDaniel P. Berrange } else { 39d5f04223SDaniel P. Berrange VNC_DEBUG("TLS handshake complete, starting websocket handshake\n"); 40a75d6f07SBrandon Carpenter if (vs->ioc_tag) { 41a75d6f07SBrandon Carpenter g_source_remove(vs->ioc_tag); 42a75d6f07SBrandon Carpenter } 432cc45228SDaniel P. Berrange vs->ioc_tag = qio_channel_add_watch( 442cc45228SDaniel P. Berrange QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL); 450057a0d5STim Hardeck } 462cc45228SDaniel P. Berrange } 472cc45228SDaniel P. Berrange 480057a0d5STim Hardeck 4904d2529dSDaniel P. Berrange gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, 5004d2529dSDaniel P. Berrange GIOCondition condition G_GNUC_UNUSED, 5104d2529dSDaniel P. Berrange void *opaque) 520057a0d5STim Hardeck { 532cc45228SDaniel P. Berrange VncState *vs = opaque; 542cc45228SDaniel P. Berrange QIOChannelTLS *tls; 553e305e4aSDaniel P. Berrange Error *err = NULL; 560057a0d5STim Hardeck 572cc45228SDaniel P. Berrange if (vs->ioc_tag) { 582cc45228SDaniel P. Berrange g_source_remove(vs->ioc_tag); 592cc45228SDaniel P. Berrange vs->ioc_tag = 0; 602cc45228SDaniel P. Berrange } 612cc45228SDaniel P. Berrange 622cc45228SDaniel P. Berrange tls = qio_channel_tls_new_server( 632cc45228SDaniel P. Berrange vs->ioc, 642cc45228SDaniel P. Berrange vs->vd->tlscreds, 653e305e4aSDaniel P. Berrange vs->vd->tlsaclname, 663e305e4aSDaniel P. Berrange &err); 672cc45228SDaniel P. Berrange if (!tls) { 682cc45228SDaniel P. Berrange VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err)); 693e305e4aSDaniel P. Berrange error_free(err); 703e305e4aSDaniel P. Berrange vnc_client_error(vs); 7104d2529dSDaniel P. Berrange return TRUE; 7251941e46SDaniel P. Berrange } 733e305e4aSDaniel P. Berrange 7410bcfe58SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(tls), "vnc-ws-server-tls"); 7510bcfe58SDaniel P. Berrange 762cc45228SDaniel P. Berrange object_unref(OBJECT(vs->ioc)); 772cc45228SDaniel P. Berrange vs->ioc = QIO_CHANNEL(tls); 78ad6374c4SDaniel P. Berrange trace_vnc_client_io_wrap(vs, vs->ioc, "tls"); 792cc45228SDaniel P. Berrange vs->tls = qio_channel_tls_get_session(tls); 802cc45228SDaniel P. Berrange 812cc45228SDaniel P. Berrange qio_channel_tls_handshake(tls, 822cc45228SDaniel P. Berrange vncws_tls_handshake_done, 832cc45228SDaniel P. Berrange vs, 84*1939ccdaSPeter Xu NULL, 852cc45228SDaniel P. Berrange NULL); 862cc45228SDaniel P. Berrange 8704d2529dSDaniel P. Berrange return TRUE; 880057a0d5STim Hardeck } 890057a0d5STim Hardeck 90d5f04223SDaniel P. Berrange 9160e705c5SDaniel P. Berrange static void vncws_handshake_done(QIOTask *task, 92d5f04223SDaniel P. Berrange gpointer user_data) 937536ee4bSTim Hardeck { 94d5f04223SDaniel P. Berrange VncState *vs = user_data; 9560e705c5SDaniel P. Berrange Error *err = NULL; 967536ee4bSTim Hardeck 9760e705c5SDaniel P. Berrange if (qio_task_propagate_error(task, &err)) { 98d5f04223SDaniel P. Berrange VNC_DEBUG("Websock handshake failed %s\n", error_get_pretty(err)); 99d5f04223SDaniel P. Berrange vnc_client_error(vs); 10060e705c5SDaniel P. Berrange error_free(err); 101d5f04223SDaniel P. Berrange } else { 102d5f04223SDaniel P. Berrange VNC_DEBUG("Websock handshake complete, starting VNC protocol\n"); 103dbee9897SDaniel P. Berrange vnc_start_protocol(vs); 104a75d6f07SBrandon Carpenter if (vs->ioc_tag) { 105a75d6f07SBrandon Carpenter g_source_remove(vs->ioc_tag); 106a75d6f07SBrandon Carpenter } 10704d2529dSDaniel P. Berrange vs->ioc_tag = qio_channel_add_watch( 10804d2529dSDaniel P. Berrange vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); 1097536ee4bSTim Hardeck } 1107536ee4bSTim Hardeck } 1117536ee4bSTim Hardeck 1127536ee4bSTim Hardeck 11304d2529dSDaniel P. Berrange gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, 11404d2529dSDaniel P. Berrange GIOCondition condition G_GNUC_UNUSED, 11504d2529dSDaniel P. Berrange void *opaque) 11604d2529dSDaniel P. Berrange { 11704d2529dSDaniel P. Berrange VncState *vs = opaque; 118d5f04223SDaniel P. Berrange QIOChannelWebsock *wioc; 11904d2529dSDaniel P. Berrange 12004d2529dSDaniel P. Berrange if (vs->ioc_tag) { 12104d2529dSDaniel P. Berrange g_source_remove(vs->ioc_tag); 122d5f04223SDaniel P. Berrange vs->ioc_tag = 0; 1237536ee4bSTim Hardeck } 1247536ee4bSTim Hardeck 125d5f04223SDaniel P. Berrange wioc = qio_channel_websock_new_server(vs->ioc); 12610bcfe58SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(wioc), "vnc-ws-server-websock"); 1277536ee4bSTim Hardeck 128d5f04223SDaniel P. Berrange object_unref(OBJECT(vs->ioc)); 129d5f04223SDaniel P. Berrange vs->ioc = QIO_CHANNEL(wioc); 130ad6374c4SDaniel P. Berrange trace_vnc_client_io_wrap(vs, vs->ioc, "websock"); 1317536ee4bSTim Hardeck 132d5f04223SDaniel P. Berrange qio_channel_websock_handshake(wioc, 133d5f04223SDaniel P. Berrange vncws_handshake_done, 134d5f04223SDaniel P. Berrange vs, 135d5f04223SDaniel P. Berrange NULL); 1367536ee4bSTim Hardeck 137d5f04223SDaniel P. Berrange return TRUE; 1387536ee4bSTim Hardeck } 139