vnc-ws.c 4.2 KB

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