aboutsummaryrefslogtreecommitdiff
path: root/ui/vnc-ws.c
diff options
context:
space:
mode:
Diffstat (limited to 'ui/vnc-ws.c')
-rw-r--r--ui/vnc-ws.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index 3e3020916c..df89315733 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -20,6 +20,69 @@
#include "vnc.h"
+#ifdef CONFIG_VNC_TLS
+#include "qemu/sockets.h"
+
+static void vncws_tls_handshake_io(void *opaque);
+
+static int vncws_start_tls_handshake(struct VncState *vs)
+{
+ int ret = gnutls_handshake(vs->ws_tls.session);
+
+ if (ret < 0) {
+ if (!gnutls_error_is_fatal(ret)) {
+ VNC_DEBUG("Handshake interrupted (blocking)\n");
+ if (!gnutls_record_get_direction(vs->ws_tls.session)) {
+ qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io,
+ NULL, vs);
+ } else {
+ qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io,
+ vs);
+ }
+ return 0;
+ }
+ VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
+ vnc_client_error(vs);
+ return -1;
+ }
+
+ VNC_DEBUG("Handshake done, switching to TLS data mode\n");
+ vs->ws_tls.wiremode = VNC_WIREMODE_TLS;
+ qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs);
+
+ return 0;
+}
+
+static void vncws_tls_handshake_io(void *opaque)
+{
+ struct VncState *vs = (struct VncState *)opaque;
+
+ VNC_DEBUG("Handshake IO continue\n");
+ vncws_start_tls_handshake(vs);
+}
+
+void vncws_tls_handshake_peek(void *opaque)
+{
+ VncState *vs = opaque;
+ long ret;
+
+ if (!vs->ws_tls.session) {
+ char peek[4];
+ ret = qemu_recv(vs->csock, peek, sizeof(peek), MSG_PEEK);
+ if (ret && (strncmp(peek, "\x16", 1) == 0
+ || strncmp(peek, "\x80", 1) == 0)) {
+ VNC_DEBUG("TLS Websocket connection recognized");
+ vnc_tls_client_setup(vs, 1);
+ vncws_start_tls_handshake(vs);
+ } else {
+ vncws_handshake_read(vs);
+ }
+ } else {
+ qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs);
+ }
+}
+#endif /* CONFIG_VNC_TLS */
+
void vncws_handshake_read(void *opaque)
{
VncState *vs = opaque;