@@ -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 */
@@ -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;
}
@@ -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);
@@ -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;
@@ -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;
@@ -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);
@@ -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)
@@ -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));
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(-)