qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

vnc-ws.c (4286B)


      1 /*
      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 
     21 #include "qemu/osdep.h"
     22 #include "qapi/error.h"
     23 #include "vnc.h"
     24 #include "io/channel-websock.h"
     25 #include "qemu/bswap.h"
     26 #include "trace.h"
     27 
     28 static void vncws_tls_handshake_done(QIOTask *task,
     29                                      gpointer user_data)
     30 {
     31     VncState *vs = user_data;
     32     Error *err = NULL;
     33 
     34     if (qio_task_propagate_error(task, &err)) {
     35         VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
     36         vnc_client_error(vs);
     37         error_free(err);
     38     } else {
     39         VNC_DEBUG("TLS handshake complete, starting websocket handshake\n");
     40         if (vs->ioc_tag) {
     41             g_source_remove(vs->ioc_tag);
     42         }
     43         vs->ioc_tag = qio_channel_add_watch(
     44             QIO_CHANNEL(vs->ioc), G_IO_IN | G_IO_HUP | G_IO_ERR,
     45             vncws_handshake_io, vs, NULL);
     46     }
     47 }
     48 
     49 
     50 gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
     51                                 GIOCondition condition,
     52                                 void *opaque)
     53 {
     54     VncState *vs = opaque;
     55     QIOChannelTLS *tls;
     56     Error *err = NULL;
     57 
     58     if (vs->ioc_tag) {
     59         g_source_remove(vs->ioc_tag);
     60         vs->ioc_tag = 0;
     61     }
     62 
     63     if (condition & (G_IO_HUP | G_IO_ERR)) {
     64         vnc_client_error(vs);
     65         return TRUE;
     66     }
     67 
     68     tls = qio_channel_tls_new_server(
     69         vs->ioc,
     70         vs->vd->tlscreds,
     71         vs->vd->tlsauthzid,
     72         &err);
     73     if (!tls) {
     74         VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
     75         error_free(err);
     76         vnc_client_error(vs);
     77         return TRUE;
     78     }
     79 
     80     qio_channel_set_name(QIO_CHANNEL(tls), "vnc-ws-server-tls");
     81 
     82     object_unref(OBJECT(vs->ioc));
     83     vs->ioc = QIO_CHANNEL(tls);
     84     trace_vnc_client_io_wrap(vs, vs->ioc, "tls");
     85     vs->tls = qio_channel_tls_get_session(tls);
     86 
     87     qio_channel_tls_handshake(tls,
     88                               vncws_tls_handshake_done,
     89                               vs,
     90                               NULL,
     91                               NULL);
     92 
     93     return TRUE;
     94 }
     95 
     96 
     97 static void vncws_handshake_done(QIOTask *task,
     98                                  gpointer user_data)
     99 {
    100     VncState *vs = user_data;
    101     Error *err = NULL;
    102 
    103     if (qio_task_propagate_error(task, &err)) {
    104         VNC_DEBUG("Websock handshake failed %s\n", error_get_pretty(err));
    105         vnc_client_error(vs);
    106         error_free(err);
    107     } else {
    108         VNC_DEBUG("Websock handshake complete, starting VNC protocol\n");
    109         vnc_start_protocol(vs);
    110         if (vs->ioc_tag) {
    111             g_source_remove(vs->ioc_tag);
    112         }
    113         vs->ioc_tag = qio_channel_add_watch(
    114             vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR,
    115             vnc_client_io, vs, NULL);
    116     }
    117 }
    118 
    119 
    120 gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
    121                             GIOCondition condition,
    122                             void *opaque)
    123 {
    124     VncState *vs = opaque;
    125     QIOChannelWebsock *wioc;
    126 
    127     if (vs->ioc_tag) {
    128         g_source_remove(vs->ioc_tag);
    129         vs->ioc_tag = 0;
    130     }
    131 
    132     if (condition & (G_IO_HUP | G_IO_ERR)) {
    133         vnc_client_error(vs);
    134         return TRUE;
    135     }
    136 
    137     wioc = qio_channel_websock_new_server(vs->ioc);
    138     qio_channel_set_name(QIO_CHANNEL(wioc), "vnc-ws-server-websock");
    139 
    140     object_unref(OBJECT(vs->ioc));
    141     vs->ioc = QIO_CHANNEL(wioc);
    142     trace_vnc_client_io_wrap(vs, vs->ioc, "websock");
    143 
    144     qio_channel_websock_handshake(wioc,
    145                                   vncws_handshake_done,
    146                                   vs,
    147                                   NULL);
    148 
    149     return TRUE;
    150 }