From: "Daniel P. Berrange" <berrange@redhat.com>
To: qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>,
Gerd Hoffmann <kraxel@redhat.com>,
Stefan Hajnoczi <stefanha@redhat.com>
Subject: [Qemu-devel] [PATCH v1 RFC 29/34] ui: convert VNC server to use QEMUIOChannelSocket classes
Date: Fri, 17 Apr 2015 15:22:32 +0100 [thread overview]
Message-ID: <1429280557-8887-30-git-send-email-berrange@redhat.com> (raw)
In-Reply-To: <1429280557-8887-1-git-send-email-berrange@redhat.com>
The minimal first step conversion to use QEMUIOChannelSocket
classes instead of directly using POSIX sockets API. This
will later be extended to also cover the TLS, SASL and
websockets code.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
ui/vnc-auth-sasl.c | 39 ++--
ui/vnc-auth-vencrypt.c | 45 ++--
ui/vnc-jobs.c | 12 +-
ui/vnc-tls.c | 24 +--
ui/vnc-ws.c | 53 +++--
ui/vnc-ws.h | 8 +-
ui/vnc.c | 545 +++++++++++++++++++++++++------------------------
ui/vnc.h | 33 ++-
8 files changed, 422 insertions(+), 337 deletions(-)
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 9733dfc..7851037 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -62,7 +62,7 @@ long vnc_client_write_sasl(VncState *vs)
(const char **)&vs->sasl.encoded,
&vs->sasl.encodedLength);
if (err != SASL_OK)
- return vnc_client_io_error(vs, -1, EIO);
+ return vnc_client_io_error(vs, -1, NULL);
vs->sasl.encodedOffset = 0;
}
@@ -86,7 +86,11 @@ long vnc_client_write_sasl(VncState *vs)
* SASL encoded output
*/
if (vs->output.offset == 0) {
- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vnc_client_io, vs);
}
return ret;
@@ -110,7 +114,7 @@ long vnc_client_read_sasl(VncState *vs)
&decoded, &decodedLen);
if (err != SASL_OK)
- return vnc_client_io_error(vs, -1, -EIO);
+ return vnc_client_io_error(vs, -1, NULL);
VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n",
encoded, ret, decoded, decodedLen);
qio_buffer_reserve(&vs->input, decodedLen);
@@ -255,17 +259,17 @@ static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t le
vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
} else {
if (!vnc_auth_sasl_check_ssf(vs)) {
- VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
+ VNC_DEBUG("Authentication rejected for weak SSF %p\n", vs->ioc);
goto authreject;
}
/* Check username whitelist ACL */
if (vnc_auth_sasl_check_access(vs) < 0) {
- VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
+ VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc);
goto authreject;
}
- VNC_DEBUG("Authentication successful %d\n", vs->csock);
+ VNC_DEBUG("Authentication successful %p\n", vs->ioc);
vnc_write_u32(vs, 0); /* Accept auth */
/*
* Delay writing in SSF encoded mode until pending output
@@ -383,17 +387,17 @@ static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t l
vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
} else {
if (!vnc_auth_sasl_check_ssf(vs)) {
- VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
+ VNC_DEBUG("Authentication rejected for weak SSF %p\n", vs->ioc);
goto authreject;
}
/* Check username whitelist ACL */
if (vnc_auth_sasl_check_access(vs) < 0) {
- VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
+ VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc);
goto authreject;
}
- VNC_DEBUG("Authentication successful %d\n", vs->csock);
+ VNC_DEBUG("Authentication successful %p\n", vs->ioc);
vnc_write_u32(vs, 0); /* Accept auth */
start_client_init(vs);
}
@@ -495,13 +499,16 @@ void start_auth_sasl(VncState *vs)
char *localAddr, *remoteAddr;
int mechlistlen;
- VNC_DEBUG("Initialize SASL auth %d\n", vs->csock);
+ VNC_DEBUG("Initialize SASL auth %p\n", vs->ioc);
/* Get local & remote client addresses in form IPADDR;PORT */
- if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock)))
+ localAddr = vnc_socket_local_addr(vs->sioc, "%s;%s", NULL);
+ if (!localAddr) {
goto authabort;
+ }
- if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) {
+ remoteAddr = vnc_socket_remote_addr(vs->sioc, "%s;%s", NULL);
+ if (!remoteAddr) {
g_free(localAddr);
goto authabort;
}
@@ -533,7 +540,8 @@ void start_auth_sasl(VncState *vs)
sasl_ssf_t ssf;
cipher = gnutls_cipher_get(vs->tls.session);
- if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
+ ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher);
+ if (!ssf) {
VNC_DEBUG("%s", "cannot TLS get cipher size\n");
sasl_dispose(&vs->sasl.conn);
vs->sasl.conn = NULL;
@@ -549,9 +557,12 @@ void start_auth_sasl(VncState *vs)
vs->sasl.conn = NULL;
goto authabort;
}
- } else
+ } else {
#endif /* CONFIG_VNC_TLS */
vs->sasl.wantSSF = 1;
+#ifdef CONFIG_VNC_TLS
+ }
+#endif
memset (&secprops, 0, sizeof secprops);
/* Inform SASL that we've got an external SSF layer from TLS */
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
index a420ccb..55f24e4 100644
--- a/ui/vnc-auth-vencrypt.c
+++ b/ui/vnc-auth-vencrypt.c
@@ -63,23 +63,32 @@ static void start_auth_vencrypt_subauth(VncState *vs)
}
}
-static void vnc_tls_handshake_io(void *opaque);
+static gboolean vnc_tls_handshake_io(QIOChannel *ioc,
+ GIOCondition condition,
+ void *opaque);
static int vnc_start_vencrypt_handshake(struct VncState *vs) {
int ret;
if ((ret = gnutls_handshake(vs->tls.session)) < 0) {
- if (!gnutls_error_is_fatal(ret)) {
- VNC_DEBUG("Handshake interrupted (blocking)\n");
- if (!gnutls_record_get_direction(vs->tls.session))
- qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
- else
- qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
- return 0;
- }
- VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
- vnc_client_error(vs);
- return -1;
+ if (!gnutls_error_is_fatal(ret)) {
+ GIOCondition condition;
+ VNC_DEBUG("Handshake interrupted (blocking)\n");
+ if (!gnutls_record_get_direction(vs->tls.session)) {
+ condition = G_IO_IN;
+ } else {
+ condition = G_IO_OUT;
+ }
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, condition, vnc_tls_handshake_io, vs);
+ return 0;
+ }
+ VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
+ vnc_client_error(vs);
+ return -1;
}
if (vs->vd->tls.x509verify) {
@@ -93,18 +102,26 @@ static int vnc_start_vencrypt_handshake(struct VncState *vs) {
}
VNC_DEBUG("Handshake done, switching to TLS data mode\n");
- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs);
start_auth_vencrypt_subauth(vs);
return 0;
}
-static void vnc_tls_handshake_io(void *opaque) {
+static gboolean vnc_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
+ GIOCondition condition G_GNUC_UNUSED,
+ void *opaque)
+{
struct VncState *vs = (struct VncState *)opaque;
VNC_DEBUG("Handshake IO continue\n");
vnc_start_vencrypt_handshake(vs);
+ return TRUE;
}
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 333c35e..3262ac6 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -168,7 +168,7 @@ void vnc_jobs_consume_buffer(VncState *vs)
vnc_write(vs, vs->jobs_buffer.buffer, vs->jobs_buffer.offset);
qio_buffer_reset(&vs->jobs_buffer);
}
- flush = vs->csock != -1 && vs->abort != true;
+ flush = vs->ioc != NULL && vs->abort != true;
vnc_unlock_output(vs);
if (flush) {
@@ -193,7 +193,8 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
local->hextile = orig->hextile;
local->zrle = orig->zrle;
local->output = queue->buffer;
- local->csock = -1; /* Don't do any network work on this thread */
+ local->sioc = NULL; /* Don't do any network work on this thread */
+ local->ioc = NULL; /* Don't do any network work on this thread */
qio_buffer_reset(&local->output);
}
@@ -230,7 +231,7 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
}
vnc_lock_output(job->vs);
- if (job->vs->csock == -1 || job->vs->abort == true) {
+ if (job->vs->ioc == NULL || job->vs->abort == true) {
vnc_unlock_output(job->vs);
goto disconnected;
}
@@ -250,7 +251,7 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
int n;
- if (job->vs->csock == -1) {
+ if (job->vs->ioc == NULL) {
vnc_unlock_display(job->vs->vd);
/* Copy persistent encoding data */
vnc_async_encoding_end(job->vs, &vs);
@@ -272,8 +273,7 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
vnc_lock_output(job->vs);
-
- if (job->vs->csock != -1) {
+ if (job->vs->ioc != NULL) {
qio_buffer_reserve(&job->vs->jobs_buffer, vs.output.offset);
qio_buffer_append(&job->vs->jobs_buffer, vs.output.buffer,
vs.output.offset);
diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c
index eddd39b..17e1c8f 100644
--- a/ui/vnc-tls.c
+++ b/ui/vnc-tls.c
@@ -69,13 +69,13 @@ static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
const void *data,
size_t len) {
struct VncState *vs = (struct VncState *)transport;
- int ret;
-
- retry:
- ret = send(vs->csock, data, len, 0);
+ ssize_t ret = qio_channel_write(vs->ioc, data, len, NULL);
if (ret < 0) {
- if (errno == EINTR)
- goto retry;
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
+ errno = EAGAIN;
+ } else {
+ errno = EIO;
+ }
return -1;
}
return ret;
@@ -86,13 +86,13 @@ static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
void *data,
size_t len) {
struct VncState *vs = (struct VncState *)transport;
- int ret;
-
- retry:
- ret = qemu_recv(vs->csock, data, len, 0);
+ ssize_t ret = qio_channel_read(vs->ioc, data, len, NULL);
if (ret < 0) {
- if (errno == EINTR)
- goto retry;
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
+ errno = EAGAIN;
+ } else {
+ errno = EIO;
+ }
return -1;
}
return ret;
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index d3ca97e..ad22694 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -25,20 +25,26 @@
#ifdef CONFIG_VNC_TLS
#include "qemu/sockets.h"
+static void vncws_handshake_read(VncState *vs);
+
static int vncws_start_tls_handshake(struct VncState *vs)
{
int ret = gnutls_handshake(vs->tls.session);
if (ret < 0) {
if (!gnutls_error_is_fatal(ret)) {
+ GIOCondition condition;
VNC_DEBUG("Handshake interrupted (blocking)\n");
if (!gnutls_record_get_direction(vs->tls.session)) {
- qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io,
- NULL, vs);
+ condition = G_IO_IN;
} else {
- qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io,
- vs);
+ condition = G_IO_OUT;
+ }
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
}
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, condition, vncws_tls_handshake_io, vs);
return 0;
}
VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
@@ -57,29 +63,35 @@ static int vncws_start_tls_handshake(struct VncState *vs)
}
VNC_DEBUG("Handshake done, switching to TLS data mode\n");
- qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs);
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vncws_handshake_io, vs);
return 0;
}
-void vncws_tls_handshake_io(void *opaque)
+gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
+ GIOCondition condition G_GNUC_UNUSED,
+ void *opaque)
{
struct VncState *vs = (struct VncState *)opaque;
if (!vs->tls.session) {
VNC_DEBUG("TLS Websocket setup\n");
if (vnc_tls_client_setup(vs, vs->vd->tls.x509cert != NULL) < 0) {
- return;
+ return TRUE;
}
}
VNC_DEBUG("Handshake IO continue\n");
vncws_start_tls_handshake(vs);
+ return TRUE;
}
#endif /* CONFIG_VNC_TLS */
-void vncws_handshake_read(void *opaque)
+static void vncws_handshake_read(VncState *vs)
{
- VncState *vs = opaque;
uint8_t *handshake_end;
long ret;
/* Typical HTTP headers from novnc are 512 bytes, so limiting
@@ -89,7 +101,7 @@ void vncws_handshake_read(void *opaque)
ret = vnc_client_read_buf(vs, qio_buffer_end(&vs->ws_input), want);
if (!ret) {
- if (vs->csock == -1) {
+ if (vs->disconnecting) {
vnc_disconnect_finish(vs);
}
return;
@@ -99,7 +111,11 @@ void vncws_handshake_read(void *opaque)
handshake_end = (uint8_t *)g_strstr_len((char *)vs->ws_input.buffer,
vs->ws_input.offset, WS_HANDSHAKE_END);
if (handshake_end) {
- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vnc_client_io, vs);
vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset);
qio_buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer +
strlen(WS_HANDSHAKE_END));
@@ -110,6 +126,15 @@ void vncws_handshake_read(void *opaque)
}
+gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
+ GIOCondition condition G_GNUC_UNUSED,
+ void *opaque)
+{
+ VncState *vs = opaque;
+ vncws_handshake_read(vs);
+ return TRUE;
+}
+
long vnc_client_read_ws(VncState *vs)
{
int ret, err;
@@ -177,7 +202,11 @@ long vnc_client_write_ws(VncState *vs)
qio_buffer_advance(&vs->ws_output, ret);
if (vs->ws_output.offset == 0) {
- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vnc_client_io, vs);
}
return ret;
diff --git a/ui/vnc-ws.h b/ui/vnc-ws.h
index 5437102..2e79324 100644
--- a/ui/vnc-ws.h
+++ b/ui/vnc-ws.h
@@ -73,9 +73,13 @@ enum {
};
#ifdef CONFIG_VNC_TLS
-void vncws_tls_handshake_io(void *opaque);
+gboolean vncws_tls_handshake_io(QIOChannel *ioc,
+ GIOCondition condition,
+ void *opaque);
#endif /* CONFIG_VNC_TLS */
-void vncws_handshake_read(void *opaque);
+gboolean vncws_handshake_io(QIOChannel *ioc,
+ GIOCondition condition,
+ void *opaque);
long vnc_client_write_ws(VncState *vs);
long vnc_client_read_ws(VncState *vs);
void vncws_process_handshake(VncState *vs, uint8_t *line, size_t size);
diff --git a/ui/vnc.c b/ui/vnc.c
index af1f792..6c08711 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -40,6 +40,8 @@
#include "qapi-event.h"
#include "crypto/hash.h"
+#include <glib/gi18n.h>
+
#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
#define VNC_REFRESH_INTERVAL_INC 50
#define VNC_REFRESH_INTERVAL_MAX GUI_REFRESH_INTERVAL_IDLE
@@ -65,8 +67,8 @@ static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
[VNC_SHARE_MODE_EXCLUSIVE] = "exclusive",
[VNC_SHARE_MODE_DISCONNECTED] = "disconnected",
};
- fprintf(stderr, "%s/%d: %s -> %s\n", __func__,
- vs->csock, mn[vs->share_mode], mn[mode]);
+ fprintf(stderr, "%s/%p: %s -> %s\n", __func__,
+ vs->ioc, mn[vs->share_mode], mn[mode]);
#endif
switch (vs->share_mode) {
@@ -100,105 +102,74 @@ static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
}
}
-static char *addr_to_string(const char *format,
- struct sockaddr_storage *sa,
- socklen_t salen) {
- char *addr;
- char host[NI_MAXHOST];
- char serv[NI_MAXSERV];
- int err;
- size_t addrlen;
-
- if ((err = getnameinfo((struct sockaddr *)sa, salen,
- host, sizeof(host),
- serv, sizeof(serv),
- NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
- VNC_DEBUG("Cannot resolve address %d: %s\n",
- err, gai_strerror(err));
- return NULL;
- }
-
- /* Enough for the existing format + the 2 vars we're
- * substituting in. */
- addrlen = strlen(format) + strlen(host) + strlen(serv);
- addr = g_malloc(addrlen + 1);
- snprintf(addr, addrlen, format, host, serv);
- addr[addrlen] = '\0';
-
- return addr;
-}
-
-
-char *vnc_socket_local_addr(const char *format, int fd) {
- struct sockaddr_storage sa;
- socklen_t salen;
- salen = sizeof(sa);
- if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0)
- return NULL;
-
- return addr_to_string(format, &sa, salen);
-}
-
-char *vnc_socket_remote_addr(const char *format, int fd) {
- struct sockaddr_storage sa;
- socklen_t salen;
+char *
+vnc_socket_local_addr(QIOChannelSocket *ioc,
+ const char *format,
+ Error **errp)
+{
+ char *host, *serv, *ret;
+ NetworkAddressFamily family;
- salen = sizeof(sa);
- if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
+ if (qio_channel_socket_get_local_addr_string(
+ ioc, &host, &serv, &family, errp) < 0) {
return NULL;
+ }
- return addr_to_string(format, &sa, salen);
+ ret = g_strdup_printf(format, host, serv);
+ g_free(host);
+ g_free(serv);
+ return ret;
}
-static VncBasicInfo *vnc_basic_info_get(struct sockaddr_storage *sa,
- socklen_t salen)
+char *
+vnc_socket_remote_addr(QIOChannelSocket *ioc,
+ const char *format,
+ Error **errp)
{
- VncBasicInfo *info;
- char host[NI_MAXHOST];
- char serv[NI_MAXSERV];
- int err;
-
- if ((err = getnameinfo((struct sockaddr *)sa, salen,
- host, sizeof(host),
- serv, sizeof(serv),
- NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
- VNC_DEBUG("Cannot resolve address %d: %s\n",
- err, gai_strerror(err));
+ char *host, *serv, *ret;
+ NetworkAddressFamily family;
+
+ if (qio_channel_socket_get_remote_addr_string(
+ ioc, &host, &serv, &family, errp) < 0) {
return NULL;
}
- info = g_malloc0(sizeof(VncBasicInfo));
- info->host = g_strdup(host);
- info->service = g_strdup(serv);
- info->family = inet_netfamily(sa->ss_family);
- return info;
+ ret = g_strdup_printf(format, host, serv);
+ g_free(host);
+ g_free(serv);
+ return ret;
}
-static VncBasicInfo *vnc_basic_info_get_from_server_addr(int fd)
+
+static VncBasicInfo *
+vnc_basic_info_get_from_server_addr(QIOChannelSocket *ioc,
+ Error **errp)
{
- struct sockaddr_storage sa;
- socklen_t salen;
+ VncBasicInfo *info = g_new0(VncBasicInfo, 1);
- salen = sizeof(sa);
- if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
+ if (qio_channel_socket_get_local_addr_string(
+ ioc, &info->host, &info->service,
+ &info->family, errp) < 0) {
+ g_free(info);
return NULL;
}
-
- return vnc_basic_info_get(&sa, salen);
+ return info;
}
-static VncBasicInfo *vnc_basic_info_get_from_remote_addr(int fd)
+static VncBasicInfo *
+vnc_basic_info_get_from_remote_addr(QIOChannelSocket *ioc,
+ Error **errp)
{
- struct sockaddr_storage sa;
- socklen_t salen;
+ VncBasicInfo *info = g_new0(VncBasicInfo, 1);
- salen = sizeof(sa);
- if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
+ if (qio_channel_socket_get_remote_addr_string(
+ ioc, &info->host, &info->service,
+ &info->family, errp) < 0) {
+ g_free(info);
return NULL;
}
-
- return vnc_basic_info_get(&sa, salen);
+ return info;
}
static const char *vnc_auth_name(VncDisplay *vd) {
@@ -255,8 +226,11 @@ static const char *vnc_auth_name(VncDisplay *vd) {
static VncServerInfo *vnc_server_info_get(VncDisplay *vd)
{
VncServerInfo *info;
- VncBasicInfo *bi = vnc_basic_info_get_from_server_addr(vd->lsock);
+ Error *err = NULL;
+ VncBasicInfo *bi = vnc_basic_info_get_from_server_addr(
+ vd->lsock, &err);
if (!bi) {
+ error_free(err);
return NULL;
}
@@ -291,11 +265,15 @@ static void vnc_client_cache_auth(VncState *client)
static void vnc_client_cache_addr(VncState *client)
{
- VncBasicInfo *bi = vnc_basic_info_get_from_remote_addr(client->csock);
+ Error *err = NULL;
+ VncBasicInfo *bi = vnc_basic_info_get_from_remote_addr(
+ client->sioc, &err);
if (bi) {
client->info = g_malloc0(sizeof(*client->info));
client->info->base = bi;
+ } else {
+ error_free(err);
}
}
@@ -332,28 +310,19 @@ static void vnc_qmp_event(VncState *vs, QAPIEvent event)
static VncClientInfo *qmp_query_vnc_client(const VncState *client)
{
- struct sockaddr_storage sa;
- socklen_t salen = sizeof(sa);
- char host[NI_MAXHOST];
- char serv[NI_MAXSERV];
VncClientInfo *info;
+ VncBasicInfo *binfo;
+ Error *err = NULL;
- if (getpeername(client->csock, (struct sockaddr *)&sa, &salen) < 0) {
- return NULL;
- }
-
- if (getnameinfo((struct sockaddr *)&sa, salen,
- host, sizeof(host),
- serv, sizeof(serv),
- NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
+ binfo = vnc_basic_info_get_from_remote_addr(
+ client->sioc, &err);
+ if (!binfo) {
+ error_free(err);
return NULL;
}
info = g_malloc0(sizeof(*info));
- info->base = g_malloc0(sizeof(*info->base));
- info->base->host = g_strdup(host);
- info->base->service = g_strdup(serv);
- info->base->family = inet_netfamily(sa.ss_family);
+ info->base = binfo;
info->base->websocket = client->websocket;
#ifdef CONFIG_VNC_TLS
@@ -409,43 +378,25 @@ VncInfo *qmp_query_vnc(Error **errp)
if (vd == NULL || !vd->enabled) {
info->enabled = false;
} else {
- struct sockaddr_storage sa;
- socklen_t salen = sizeof(sa);
- char host[NI_MAXHOST];
- char serv[NI_MAXSERV];
-
info->enabled = true;
/* for compatibility with the original command */
info->has_clients = true;
info->clients = qmp_query_client_list(vd);
- if (vd->lsock == -1) {
+ if (vd->lsock == NULL) {
return info;
}
- if (getsockname(vd->lsock, (struct sockaddr *)&sa,
- &salen) == -1) {
- error_set(errp, QERR_UNDEFINED_ERROR);
- goto out_error;
- }
-
- if (getnameinfo((struct sockaddr *)&sa, salen,
- host, sizeof(host),
- serv, sizeof(serv),
- NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
- error_set(errp, QERR_UNDEFINED_ERROR);
+ if (qio_channel_socket_get_local_addr_string(
+ vd->lsock, &info->host, &info->service,
+ &info->family, errp) < 0) {
goto out_error;
}
info->has_host = true;
- info->host = g_strdup(host);
-
info->has_service = true;
- info->service = g_strdup(serv);
-
info->has_family = true;
- info->family = inet_netfamily(sa.ss_family);
info->has_auth = true;
info->auth = g_strdup(vnc_auth_name(vd));
@@ -458,28 +409,22 @@ out_error:
return NULL;
}
-static VncBasicInfoList *qmp_query_server_entry(int socket,
+static VncBasicInfoList *qmp_query_server_entry(QIOChannelSocket *ioc,
bool websocket,
VncBasicInfoList *prev)
{
VncBasicInfoList *list;
VncBasicInfo *info;
- struct sockaddr_storage sa;
- socklen_t salen = sizeof(sa);
- char host[NI_MAXHOST];
- char serv[NI_MAXSERV];
-
- if (getsockname(socket, (struct sockaddr *)&sa, &salen) < 0 ||
- getnameinfo((struct sockaddr *)&sa, salen,
- host, sizeof(host), serv, sizeof(serv),
- NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
- return prev;
- }
+ Error *err = NULL;
info = g_new0(VncBasicInfo, 1);
- info->host = g_strdup(host);
- info->service = g_strdup(serv);
- info->family = inet_netfamily(sa.ss_family);
+ if (qio_channel_socket_get_local_addr_string(
+ ioc, &info->host, &info->service,
+ &info->family, &err) < 0) {
+ error_free(err);
+ g_free(info);
+ return prev;
+ }
info->websocket = websocket;
list = g_new0(VncBasicInfoList, 1);
@@ -575,13 +520,13 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
info->has_display = true;
info->display = g_strdup(dev->id);
}
- if (vd->lsock != -1) {
- info->server = qmp_query_server_entry(vd->lsock, false,
- info->server);
+ if (vd->lsock != NULL) {
+ info->server = qmp_query_server_entry(
+ vd->lsock, false, info->server);
}
- if (vd->lwebsock != -1) {
- info->server = qmp_query_server_entry(vd->lwebsock, true,
- info->server);
+ if (vd->lwebsock != NULL) {
+ info->server = qmp_query_server_entry(
+ vd->lwebsock, true, info->server);
}
item = g_new0(VncInfo2List, 1);
@@ -654,7 +599,7 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
static void vnc_desktop_resize(VncState *vs)
{
- if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
+ if (vs->ioc == NULL || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
return;
}
if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
@@ -1018,7 +963,7 @@ static int find_and_clear_dirty_height(struct VncState *vs,
static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
{
vs->has_dirty += has_dirty;
- if (vs->need_update && vs->csock != -1) {
+ if (vs->need_update && vs->ioc != NULL) {
VncDisplay *vd = vs->vd;
VncJob *job;
int y;
@@ -1082,7 +1027,7 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
return n;
}
- if (vs->csock == -1) {
+ if (vs->disconnecting) {
vnc_disconnect_finish(vs);
} else if (sync) {
vnc_jobs_join(vs);
@@ -1164,12 +1109,15 @@ static void audio_del(VncState *vs)
static void vnc_disconnect_start(VncState *vs)
{
- if (vs->csock == -1)
+ if (vs->disconnecting) {
return;
+ }
vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
- qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
- closesocket(vs->csock);
- vs->csock = -1;
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ qio_channel_close(vs->ioc, NULL);
+ vs->disconnecting = TRUE;
}
void vnc_disconnect_finish(VncState *vs)
@@ -1220,29 +1168,28 @@ void vnc_disconnect_finish(VncState *vs)
g_free(vs->lossy_rect[i]);
}
g_free(vs->lossy_rect);
+
+ object_unref(OBJECT(vs->ioc));
+ vs->ioc = NULL;
+ object_unref(OBJECT(vs->sioc));
+ vs->sioc = NULL;
g_free(vs);
}
-int vnc_client_io_error(VncState *vs, int ret, int last_errno)
+int vnc_client_io_error(VncState *vs, int ret, Error **errp)
{
- if (ret == 0 || ret == -1) {
- if (ret == -1) {
- switch (last_errno) {
- case EINTR:
- case EAGAIN:
-#ifdef _WIN32
- case WSAEWOULDBLOCK:
-#endif
- return 0;
- default:
- break;
- }
+ if (ret <= 0) {
+ if (ret == 0) {
+ VNC_DEBUG("Closing down client sock: EOF\n");
+ } else if (ret != QIO_CHANNEL_ERR_BLOCK) {
+ VNC_DEBUG("Closing down client sock: ret %d (%s)\n",
+ ret, errp ? error_get_pretty(*errp) : "Unknown");
}
-
- VNC_DEBUG("Closing down client sock: ret %d, errno %d\n",
- ret, ret < 0 ? last_errno : 0);
vnc_disconnect_start(vs);
-
+ if (errp) {
+ error_free(*errp);
+ *errp = NULL;
+ }
return 0;
}
return ret;
@@ -1256,18 +1203,20 @@ void vnc_client_error(VncState *vs)
}
#ifdef CONFIG_VNC_TLS
-static long vnc_client_write_tls(gnutls_session_t *session,
- const uint8_t *data,
- size_t datalen)
+static ssize_t vnc_client_write_tls(gnutls_session_t *session,
+ const uint8_t *data,
+ size_t datalen,
+ Error **errp)
{
- long ret = gnutls_write(*session, data, datalen);
+ ssize_t ret = gnutls_write(*session, data, datalen);
if (ret < 0) {
if (ret == GNUTLS_E_AGAIN) {
- errno = EAGAIN;
+ ret = -2;
} else {
- errno = EIO;
+ ret = -1;
+ error_setg_errno(errp, -EIO, "%s",
+ _("Cannot write to TLS socket"));
}
- ret = -1;
}
return ret;
}
@@ -1288,20 +1237,22 @@ static long vnc_client_write_tls(gnutls_session_t *session,
* the requested 'datalen' if the socket would block. Returns
* -1 on error, and disconnects the client socket.
*/
-long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
+ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
{
- long ret;
+ ssize_t ret;
+ Error *err = NULL;
#ifdef CONFIG_VNC_TLS
if (vs->tls.session) {
- ret = vnc_client_write_tls(&vs->tls.session, data, datalen);
+ ret = vnc_client_write_tls(&vs->tls.session, data, datalen, &err);
} else {
#endif /* CONFIG_VNC_TLS */
- ret = send(vs->csock, (const void *)data, datalen, 0);
+ ret = qio_channel_write(
+ vs->ioc, (const char *)data, datalen, &err);
#ifdef CONFIG_VNC_TLS
}
#endif /* CONFIG_VNC_TLS */
VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
- return vnc_client_io_error(vs, ret, socket_error());
+ return vnc_client_io_error(vs, ret, &err);
}
@@ -1315,9 +1266,9 @@ long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
* the buffered output data if the socket would block. Returns
* -1 on error, and disconnects the client socket.
*/
-static long vnc_client_write_plain(VncState *vs)
+static ssize_t vnc_client_write_plain(VncState *vs)
{
- long ret;
+ ssize_t ret;
#ifdef CONFIG_VNC_SASL
VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
@@ -1339,7 +1290,11 @@ static long vnc_client_write_plain(VncState *vs)
qio_buffer_advance(&vs->output, ret);
if (vs->output.offset == 0) {
- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vnc_client_io, vs);
}
return ret;
@@ -1351,10 +1306,8 @@ static long vnc_client_write_plain(VncState *vs)
* the client socket. Will delegate actual work according to whether
* SASL SSF layers are enabled (thus requiring encryption calls)
*/
-static void vnc_client_write_locked(void *opaque)
+static void vnc_client_write_locked(VncState *vs)
{
- VncState *vs = opaque;
-
#ifdef CONFIG_VNC_SASL
if (vs->sasl.conn &&
vs->sasl.runSSF &&
@@ -1371,15 +1324,18 @@ static void vnc_client_write_locked(void *opaque)
}
}
-void vnc_client_write(void *opaque)
+static void vnc_client_write(VncState *vs)
{
- VncState *vs = opaque;
vnc_lock_output(vs);
if (vs->output.offset || vs->ws_output.offset) {
- vnc_client_write_locked(opaque);
- } else if (vs->csock != -1) {
- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+ vnc_client_write_locked(vs);
+ } else if (vs->ioc != NULL) {
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vnc_client_io, vs);
}
vnc_unlock_output(vs);
}
@@ -1391,17 +1347,18 @@ void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
}
#ifdef CONFIG_VNC_TLS
-static long vnc_client_read_tls(gnutls_session_t *session, uint8_t *data,
- size_t datalen)
+static ssize_t vnc_client_read_tls(gnutls_session_t *session, uint8_t *data,
+ size_t datalen, Error **errp)
{
- long ret = gnutls_read(*session, data, datalen);
+ ssize_t ret = gnutls_read(*session, data, datalen);
if (ret < 0) {
if (ret == GNUTLS_E_AGAIN) {
- errno = EAGAIN;
+ ret = QIO_CHANNEL_ERR_BLOCK;
} else {
- errno = EIO;
+ ret = -1;
+ error_setg_errno(errp, -EIO, "%s",
+ _("Cannot read from TLS socket"));
}
- ret = -1;
}
return ret;
}
@@ -1422,20 +1379,22 @@ static long vnc_client_read_tls(gnutls_session_t *session, uint8_t *data,
* the requested 'datalen' if the socket would block. Returns
* -1 on error, and disconnects the client socket.
*/
-long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
+ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
{
- long ret;
+ ssize_t ret;
+ Error *err = NULL;
#ifdef CONFIG_VNC_TLS
if (vs->tls.session) {
- ret = vnc_client_read_tls(&vs->tls.session, data, datalen);
+ ret = vnc_client_read_tls(&vs->tls.session, data, datalen, &err);
} else {
#endif /* CONFIG_VNC_TLS */
- ret = qemu_recv(vs->csock, data, datalen, 0);
+ ret = qio_channel_read(
+ vs->ioc, (char *)data, datalen, &err);
#ifdef CONFIG_VNC_TLS
}
#endif /* CONFIG_VNC_TLS */
VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
- return vnc_client_io_error(vs, ret, socket_error());
+ return vnc_client_io_error(vs, ret, &err);
}
@@ -1447,7 +1406,7 @@ long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
* Returns the number of bytes read. Returns -1 on error, and
* disconnects the client socket.
*/
-static long vnc_client_read_plain(VncState *vs)
+static ssize_t vnc_client_read_plain(VncState *vs)
{
int ret;
VNC_DEBUG("Read plain %p size %zd offset %zd\n",
@@ -1472,10 +1431,9 @@ static void vnc_jobs_bh(void *opaque)
* the client socket. Will delegate actual work according to whether
* SASL SSF layers are enabled (thus requiring decryption calls)
*/
-void vnc_client_read(void *opaque)
+static void vnc_client_read(VncState *vs)
{
- VncState *vs = opaque;
- long ret;
+ ssize_t ret;
#ifdef CONFIG_VNC_SASL
if (vs->sasl.conn && vs->sasl.runSSF)
@@ -1495,8 +1453,9 @@ void vnc_client_read(void *opaque)
ret = vnc_client_read_plain(vs);
}
if (!ret) {
- if (vs->csock == -1)
+ if (vs->disconnecting) {
vnc_disconnect_finish(vs);
+ }
return;
}
@@ -1505,7 +1464,7 @@ void vnc_client_read(void *opaque)
int ret;
ret = vs->read_handler(vs, vs->input.buffer, len);
- if (vs->csock == -1) {
+ if (vs->disconnecting) {
vnc_disconnect_finish(vs);
return;
}
@@ -1518,12 +1477,30 @@ void vnc_client_read(void *opaque)
}
}
+gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED,
+ GIOCondition condition, void *opaque)
+{
+ VncState *vs = opaque;
+ if (condition & G_IO_IN) {
+ vnc_client_read(vs);
+ }
+ if (condition & G_IO_OUT) {
+ vnc_client_write(vs);
+ }
+ return TRUE;
+}
+
+
void vnc_write(VncState *vs, const void *data, size_t len)
{
qio_buffer_reserve(&vs->output, len);
- if (vs->csock != -1 && qio_buffer_empty(&vs->output)) {
- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+ if (vs->ioc != NULL && qio_buffer_empty(&vs->output)) {
+ if (vs->ioc_tag) {
+ g_source_remove(vs->ioc_tag);
+ }
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs);
}
qio_buffer_append(&vs->output, data, len);
@@ -1564,8 +1541,7 @@ void vnc_write_u8(VncState *vs, uint8_t value)
void vnc_flush(VncState *vs)
{
vnc_lock_output(vs);
- if (vs->csock != -1 && (vs->output.offset ||
- vs->ws_output.offset)) {
+ if (vs->ioc != NULL && (vs->output.offset || vs->ws_output.offset)) {
vnc_client_write_locked(vs);
}
vnc_unlock_output(vs);
@@ -2946,13 +2922,16 @@ static void vnc_refresh(DisplayChangeListener *dcl)
}
}
-static void vnc_connect(VncDisplay *vd, int csock,
+static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
bool skipauth, bool websocket)
{
VncState *vs = g_malloc0(sizeof(VncState));
int i;
- vs->csock = csock;
+ vs->sioc = sioc;
+ object_ref(OBJECT(vs->sioc));
+ vs->ioc = QIO_CHANNEL(sioc);
+ object_ref(OBJECT(vs->ioc));
vs->vd = vd;
if (skipauth) {
@@ -2975,23 +2954,24 @@ static void vnc_connect(VncDisplay *vd, int csock,
vs->lossy_rect[i] = g_malloc0(VNC_STAT_COLS * sizeof (uint8_t));
}
- VNC_DEBUG("New client on socket %d\n", csock);
+ VNC_DEBUG("New client on socket %p\n", vs->sioc);
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
- qemu_set_nonblock(vs->csock);
+ qio_channel_set_blocking(vs->ioc, false);
if (websocket) {
vs->websocket = 1;
#ifdef CONFIG_VNC_TLS
if (vd->ws_tls) {
- qemu_set_fd_handler2(vs->csock, NULL, vncws_tls_handshake_io,
- NULL, vs);
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vncws_tls_handshake_io, vs);
} else
#endif /* CONFIG_VNC_TLS */
{
- qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read,
- NULL, vs);
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vncws_handshake_io, vs);
}
} else {
- qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vnc_client_io, vs);
}
vnc_client_cache_addr(vs);
@@ -3045,35 +3025,28 @@ void vnc_init_state(VncState *vs)
/* vs might be free()ed here */
}
-static void vnc_listen_read(void *opaque, bool websocket)
+static gboolean vnc_listen_io(QIOChannel *ioc,
+ GIOCondition condition,
+ void *opaque)
{
VncDisplay *vs = opaque;
- struct sockaddr_in addr;
- socklen_t addrlen = sizeof(addr);
- int csock;
+ QIOChannelSocket *sioc = NULL;
+ Error *err = NULL;
/* Catch-up */
graphic_hw_update(vs->dcl.con);
- if (websocket) {
- csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen);
+ sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), &err);
+ if (sioc != NULL) {
+ qio_channel_socket_set_nodelay(sioc, true);
+ vnc_connect(vs, sioc, false,
+ ioc != QIO_CHANNEL(vs->lsock));
+ object_unref(OBJECT(sioc));
} else {
- csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
+ /* client probably closed connection before we got there */
+ error_free(err);
}
- if (csock != -1) {
- socket_set_nodelay(csock);
- vnc_connect(vs, csock, false, websocket);
- }
-}
-
-static void vnc_listen_regular_read(void *opaque)
-{
- vnc_listen_read(opaque, false);
-}
-
-static void vnc_listen_websocket_read(void *opaque)
-{
- vnc_listen_read(opaque, true);
+ return TRUE;
}
static const DisplayChangeListenerOps dcl_ops = {
@@ -3099,9 +3072,6 @@ void vnc_display_init(const char *id)
vs->id = strdup(id);
QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
- vs->lsock = -1;
- vs->lwebsock = -1;
-
QTAILQ_INIT(&vs->clients);
vs->expires = TIME_MAX;
@@ -3129,16 +3099,20 @@ static void vnc_display_close(VncDisplay *vs)
return;
vs->enabled = false;
vs->is_unix = false;
- if (vs->lsock != -1) {
- qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
- close(vs->lsock);
- vs->lsock = -1;
+ if (vs->lsock != NULL) {
+ if (vs->lsock_tag) {
+ g_source_remove(vs->lsock_tag);
+ }
+ object_unref(OBJECT(vs->lsock));
+ vs->lsock = NULL;
}
vs->ws_enabled = false;
- if (vs->lwebsock != -1) {
- qemu_set_fd_handler2(vs->lwebsock, NULL, NULL, NULL, NULL);
- close(vs->lwebsock);
- vs->lwebsock = -1;
+ if (vs->lwebsock != NULL) {
+ if (vs->lwebsock_tag) {
+ g_source_remove(vs->lwebsock_tag);
+ }
+ object_unref(OBJECT(vs->lwebsock));
+ vs->lwebsock = NULL;
}
vs->auth = VNC_AUTH_INVALID;
vs->subauth = VNC_AUTH_INVALID;
@@ -3183,7 +3157,7 @@ char *vnc_display_local_addr(const char *id)
VncDisplay *vs = vnc_display_find(id);
assert(vs);
- return vnc_socket_local_addr("%s:%s", vs->lsock);
+ return vnc_socket_local_addr(vs->lsock, "%s:%s", NULL);
}
static QemuOptsList qemu_vnc_opts = {
@@ -3408,6 +3382,7 @@ void vnc_display_open(const char *id, Error **errp)
int acl = 0;
#endif
int lock_key_sync = 1;
+ Error *err = NULL;
if (!vs) {
error_setg(errp, "VNC display not active");
@@ -3613,8 +3588,9 @@ void vnc_display_open(const char *id, Error **errp)
if (reverse) {
/* connect to viewer */
int csock;
- vs->lsock = -1;
- vs->lwebsock = -1;
+ QIOChannelSocket *sioc = NULL;
+ vs->lsock = NULL;
+ vs->lwebsock = NULL;
if (strncmp(vnc, "unix:", 5) == 0) {
csock = unix_connect(vnc+5, errp);
} else {
@@ -3623,34 +3599,58 @@ void vnc_display_open(const char *id, Error **errp)
if (csock < 0) {
goto fail;
}
- vnc_connect(vs, csock, false, false);
+ sioc = qio_channel_socket_new_fd(csock, &err);
+ if (!sioc) {
+ close(csock);
+ goto fail;
+ }
+ vnc_connect(vs, sioc, false, false);
+ object_unref(OBJECT(sioc));
} else {
/* listen for connects */
+ char *dpy;
+ int lsock;
+ dpy = g_malloc(256);
if (strncmp(vnc, "unix:", 5) == 0) {
- vs->lsock = unix_listen(vnc+5, NULL, 0, errp);
+ lsock = unix_listen(vnc+5, NULL, 0, errp);
vs->is_unix = true;
} else {
- vs->lsock = inet_listen_opts(sopts, 5900, errp);
- if (vs->lsock < 0) {
+ lsock = inet_listen_opts(sopts, 5900, errp);
+ if (lsock < 0) {
+ g_free(dpy);
goto fail;
}
if (vs->ws_enabled) {
- vs->lwebsock = inet_listen_opts(wsopts, 0, errp);
- if (vs->lwebsock < 0) {
- if (vs->lsock != -1) {
- close(vs->lsock);
- vs->lsock = -1;
- }
+ int lwebsock;
+ lwebsock = inet_listen_opts(wsopts, 0, errp);
+ if (lwebsock < 0) {
+ close(lsock);
+ lsock = -1;
goto fail;
}
+ vs->lwebsock = qio_channel_socket_new_fd(lwebsock, &err);
+ if (!vs->lwebsock) {
+ close(lsock);
+ close(lwebsock);
+ lwebsock = lsock = -1;
+ }
}
}
vs->enabled = true;
- qemu_set_fd_handler2(vs->lsock, NULL,
- vnc_listen_regular_read, NULL, vs);
+ vs->lsock = qio_channel_socket_new_fd(lsock, &err);
+ if (!vs->lsock) {
+ object_unref(OBJECT(vs->lwebsock));
+ vs->lwebsock = NULL;
+ close(lsock);
+ goto fail;
+ }
+ vs->lsock_tag = qio_channel_add_watch(
+ QIO_CHANNEL(vs->lsock),
+ G_IO_IN, vnc_listen_io, vs);
if (vs->ws_enabled) {
- qemu_set_fd_handler2(vs->lwebsock, NULL,
- vnc_listen_websocket_read, NULL, vs);
+ vs->lwebsock_tag = qio_channel_add_watch(
+ QIO_CHANNEL(vs->lwebsock),
+ G_IO_IN, vnc_listen_io, vs);
}
}
qemu_opts_del(sopts);
@@ -3662,16 +3662,27 @@ fail:
qemu_opts_del(wsopts);
vs->enabled = false;
vs->ws_enabled = false;
+ if (err) {
+ fprintf(stderr, "Unable to initialize VNC: %s\n",
+ error_get_pretty(err));
+ error_free(err);
+ }
}
void vnc_display_add_client(const char *id, int csock, bool skipauth)
{
VncDisplay *vs = vnc_display_find(id);
+ QIOChannelSocket *sioc;
if (!vs) {
return;
}
- vnc_connect(vs, csock, skipauth, false);
+
+ sioc = qio_channel_socket_new_fd(csock, NULL);
+ if (sioc) {
+ vnc_connect(vs, sioc, skipauth, false);
+ object_unref(OBJECT(sioc));
+ }
}
static void vnc_auto_assign_id(QemuOptsList *olist, QemuOpts *opts)
diff --git a/ui/vnc.h b/ui/vnc.h
index f44a949..593e6b6 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -34,6 +34,7 @@
#include "audio/audio.h"
#include "qemu/bitmap.h"
#include "io/buffer.h"
+#include "io/channel-socket.h"
#include <zlib.h>
#include <stdbool.h>
@@ -147,8 +148,10 @@ struct VncDisplay
int num_exclusive;
int connections_limit;
VncSharePolicy share_policy;
- int lsock;
- int lwebsock;
+ QIOChannelSocket *lsock;
+ guint lsock_tag;
+ QIOChannelSocket *lwebsock;
+ guint lwebsock_tag;
bool ws_enabled;
DisplaySurface *ds;
DisplayChangeListener dcl;
@@ -251,7 +254,10 @@ struct VncJob
struct VncState
{
- int csock;
+ QIOChannelSocket *sioc; /* The underlying socket */
+ QIOChannel *ioc; /* The channel currently used for I/O */
+ guint ioc_tag;
+ gboolean disconnecting;
DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_DIRTY_BITS);
uint8_t **lossy_rect; /* Not an Array to avoid costly memcpy in
@@ -504,11 +510,12 @@ enum {
*****************************************************************************/
/* Event loop functions */
-void vnc_client_read(void *opaque);
-void vnc_client_write(void *opaque);
+gboolean vnc_client_io(QIOChannel *ioc,
+ GIOCondition condition,
+ void *opaque);
-long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
-long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
+ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen);
+ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen);
/* Protocol I/O functions */
void vnc_write(VncState *vs, const void *data, size_t len);
@@ -527,7 +534,7 @@ uint32_t read_u32(uint8_t *data, size_t offset);
/* Protocol stage functions */
void vnc_client_error(VncState *vs);
-int vnc_client_io_error(VncState *vs, int ret, int last_errno);
+int vnc_client_io_error(VncState *vs, int ret, Error **errp);
void start_client_init(VncState *vs);
void start_auth_vnc(VncState *vs);
@@ -535,8 +542,14 @@ void start_auth_vnc(VncState *vs);
/* Misc helpers */
-char *vnc_socket_local_addr(const char *format, int fd);
-char *vnc_socket_remote_addr(const char *format, int fd);
+char *
+vnc_socket_local_addr(QIOChannelSocket *ioc,
+ const char *format,
+ Error **errp);
+char *
+vnc_socket_remote_addr(QIOChannelSocket *ioc,
+ const char *format,
+ Error **errp);
static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
return (vs->features & (1 << feature));
--
2.1.0
next prev parent reply other threads:[~2015-04-17 15:59 UTC|newest]
Thread overview: 71+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-04-17 14:22 [Qemu-devel] [PATCH v1 RFC 00/34] Generic support for TLS protocol & I/O channels Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 01/34] ui: remove check for failure of qemu_acl_init() Daniel P. Berrange
2015-04-17 15:56 ` Eric Blake
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 02/34] qom: document user creatable object types in help text Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 03/34] qom: create objects in two phases Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 04/34] qom: add object_new_propv / object_new_proplist constructors Daniel P. Berrange
2015-04-17 14:55 ` Paolo Bonzini
2015-04-17 15:16 ` Daniel P. Berrange
2015-04-17 16:11 ` Eric Blake
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 05/34] qom: make enum string tables const-correct Daniel P. Berrange
2015-04-17 14:56 ` Paolo Bonzini
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 06/34] qom: add a object_property_add_enum helper method Daniel P. Berrange
2015-04-17 14:56 ` Paolo Bonzini
2015-04-17 15:01 ` Paolo Bonzini
2015-04-17 15:11 ` Daniel P. Berrange
2015-04-17 15:19 ` Paolo Bonzini
2015-04-17 15:22 ` Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 07/34] qom: don't pass string table to object_get_enum method Daniel P. Berrange
2015-04-17 15:05 ` Paolo Bonzini
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 08/34] crypto: introduce new module for computing hash digests Daniel P. Berrange
2015-05-13 17:04 ` Daniel P. Berrange
2015-05-13 17:12 ` Paolo Bonzini
2015-05-13 17:21 ` Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 09/34] crypto: move built-in AES implementation into crypto/ Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 10/34] crypto: move built-in D3DES " Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 11/34] crypto: introduce generic cipher API & built-in implementation Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 12/34] crypto: add a gcrypt cipher implementation Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 13/34] crypto: add a nettle " Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 14/34] crypto: introduce new module for handling TLS credentials Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 15/34] crypto: add sanity checking of " Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 16/34] crypto: introduce new module for handling TLS sessions Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 17/34] block: convert quorum blockdrv to use crypto APIs Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 18/34] ui: convert VNC websockets " Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 19/34] block: convert qcow/qcow2 to use generic cipher API Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 20/34] ui: convert VNC " Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 21/34] io: add abstract QIOChannel classes Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 22/34] io: add helper module for creating watches on UNIX FDs Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 23/34] io: add QIOChannelSocket class Daniel P. Berrange
2015-04-17 15:28 ` Paolo Bonzini
2015-04-17 15:52 ` Daniel P. Berrange
2015-04-17 16:00 ` Paolo Bonzini
2015-04-20 7:18 ` Gerd Hoffmann
2015-04-23 12:31 ` Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 24/34] io: add QIOChannelFile class Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 25/34] io: add QIOTask class for async operations Daniel P. Berrange
2015-04-17 15:16 ` Paolo Bonzini
2015-04-17 15:49 ` Daniel P. Berrange
2015-04-17 15:57 ` Paolo Bonzini
2015-04-17 16:11 ` Daniel P. Berrange
2015-04-17 17:06 ` Paolo Bonzini
2015-04-17 17:38 ` Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 26/34] io: add QIOChannelTLS class Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 27/34] io: pull Buffer code out of VNC module Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 28/34] io: add QIOChannelWebsock class Daniel P. Berrange
2015-04-17 14:22 ` Daniel P. Berrange [this message]
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 30/34] ui: convert VNC server to use QIOChannelTLS Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 31/34] ui: convert VNC server to use QIOChannelWebsock Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 32/34] char: convert from GIOChannel to QIOChannel Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 33/34] char: don't assume telnet initialization will not block Daniel P. Berrange
2015-04-17 14:22 ` [Qemu-devel] [PATCH v1 RFC 34/34] char: introduce support for TLS encrypted TCP chardev backend Daniel P. Berrange
2015-04-17 18:27 ` Eric Blake
2015-04-23 12:32 ` Daniel P. Berrange
2015-05-04 20:07 ` Kashyap Chamarthy
2015-05-05 13:49 ` Daniel P. Berrange
2015-05-05 13:53 ` Paolo Bonzini
2015-05-05 13:56 ` Daniel P. Berrange
2015-05-05 14:54 ` Kashyap Chamarthy
2015-05-06 8:34 ` Kashyap Chamarthy
2015-05-06 10:18 ` Daniel P. Berrange
2015-05-06 11:38 ` Kashyap Chamarthy
2015-04-23 12:28 ` [Qemu-devel] [PATCH v1 RFC 00/34] Generic support for TLS protocol & I/O channels Stefan Hajnoczi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1429280557-8887-30-git-send-email-berrange@redhat.com \
--to=berrange@redhat.com \
--cc=kraxel@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).