* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "vnc.h"
#include "vnc-jobs.h"
#include "trace.h"
#include "qapi/qmp/qerror.h"
#include "qapi/qmp/types.h"
#include "qmp-commands.h"
-#include "qemu/osdep.h"
#include "ui/input.h"
#include "qapi-event.h"
#include "crypto/hash.h"
[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) {
}
}
-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;
-
- salen = sizeof(sa);
- if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0)
- return NULL;
+static void vnc_init_basic_info(SocketAddress *addr,
+ VncBasicInfo *info,
+ Error **errp)
+{
+ switch (addr->type) {
+ case SOCKET_ADDRESS_KIND_INET:
+ info->host = g_strdup(addr->u.inet->host);
+ info->service = g_strdup(addr->u.inet->port);
+ if (addr->u.inet->ipv6) {
+ info->family = NETWORK_ADDRESS_FAMILY_IPV6;
+ } else {
+ info->family = NETWORK_ADDRESS_FAMILY_IPV4;
+ }
+ break;
- return addr_to_string(format, &sa, salen);
-}
+ case SOCKET_ADDRESS_KIND_UNIX:
+ info->host = g_strdup("");
+ info->service = g_strdup(addr->u.q_unix->path);
+ info->family = NETWORK_ADDRESS_FAMILY_UNIX;
+ break;
-static VncBasicInfo *vnc_basic_info_get(struct sockaddr_storage *sa,
- socklen_t salen)
-{
- 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));
- return NULL;
+ default:
+ error_setg(errp, "Unsupported socket kind %d",
+ addr->type);
+ break;
}
- info = g_malloc0(sizeof(VncBasicInfo));
- info->host = g_strdup(host);
- info->service = g_strdup(serv);
- info->family = inet_netfamily(sa->ss_family);
- return info;
+ return;
}
-static VncBasicInfo *vnc_basic_info_get_from_server_addr(int fd)
+static void vnc_init_basic_info_from_server_addr(QIOChannelSocket *ioc,
+ VncBasicInfo *info,
+ Error **errp)
{
- struct sockaddr_storage sa;
- socklen_t salen;
+ SocketAddress *addr = NULL;
- salen = sizeof(sa);
- if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) {
- return NULL;
+ addr = qio_channel_socket_get_local_address(ioc, errp);
+ if (!addr) {
+ return;
}
- return vnc_basic_info_get(&sa, salen);
+ vnc_init_basic_info(addr, info, errp);
+ qapi_free_SocketAddress(addr);
}
-static VncBasicInfo *vnc_basic_info_get_from_remote_addr(int fd)
+static void vnc_init_basic_info_from_remote_addr(QIOChannelSocket *ioc,
+ VncBasicInfo *info,
+ Error **errp)
{
- struct sockaddr_storage sa;
- socklen_t salen;
+ SocketAddress *addr = NULL;
- salen = sizeof(sa);
- if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) {
- return NULL;
+ addr = qio_channel_socket_get_remote_address(ioc, errp);
+ if (!addr) {
+ return;
}
- return vnc_basic_info_get(&sa, salen);
+ vnc_init_basic_info(addr, info, errp);
+ qapi_free_SocketAddress(addr);
}
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);
- if (!bi) {
- return NULL;
- }
+ Error *err = NULL;
info = g_malloc(sizeof(*info));
- info->base = bi;
+ vnc_init_basic_info_from_server_addr(vd->lsock,
+ qapi_VncServerInfo_base(info), &err);
info->has_auth = true;
info->auth = g_strdup(vnc_auth_name(vd));
+ if (err) {
+ qapi_free_VncServerInfo(info);
+ info = NULL;
+ error_free(err);
+ }
return info;
}
static void vnc_client_cache_addr(VncState *client)
{
- VncBasicInfo *bi = vnc_basic_info_get_from_remote_addr(client->csock);
+ Error *err = NULL;
- if (bi) {
- client->info = g_malloc0(sizeof(*client->info));
- client->info->base = bi;
+ client->info = g_malloc0(sizeof(*client->info));
+ vnc_init_basic_info_from_remote_addr(client->sioc,
+ qapi_VncClientInfo_base(client->info),
+ &err);
+ if (err) {
+ qapi_free_VncClientInfo(client->info);
+ client->info = NULL;
+ error_free(err);
}
}
if (!vs->info) {
return;
}
- g_assert(vs->info->base);
si = vnc_server_info_get(vs->vd);
if (!si) {
switch (event) {
case QAPI_EVENT_VNC_CONNECTED:
- qapi_event_send_vnc_connected(si, vs->info->base, &error_abort);
+ qapi_event_send_vnc_connected(si, qapi_VncClientInfo_base(vs->info),
+ &error_abort);
break;
case QAPI_EVENT_VNC_INITIALIZED:
qapi_event_send_vnc_initialized(si, vs->info, &error_abort);
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;
+ Error *err = NULL;
- if (getpeername(client->csock, (struct sockaddr *)&sa, &salen) < 0) {
- return NULL;
- }
+ info = g_malloc0(sizeof(*info));
- if (getnameinfo((struct sockaddr *)&sa, salen,
- host, sizeof(host),
- serv, sizeof(serv),
- NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
+ vnc_init_basic_info_from_remote_addr(client->sioc,
+ qapi_VncClientInfo_base(info),
+ &err);
+ if (err) {
+ error_free(err);
+ qapi_free_VncClientInfo(info);
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->websocket = client->websocket;
+ info->websocket = client->websocket;
if (client->tls) {
info->x509_dname = qcrypto_tls_session_get_peer_name(client->tls);
{
VncInfo *info = g_malloc0(sizeof(*info));
VncDisplay *vd = vnc_display_find(NULL);
+ SocketAddress *addr = NULL;
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_setg(errp, QERR_UNDEFINED_ERROR);
+ addr = qio_channel_socket_get_local_address(vd->lsock, errp);
+ if (!addr) {
goto out_error;
}
- if (getnameinfo((struct sockaddr *)&sa, salen,
- host, sizeof(host),
- serv, sizeof(serv),
- NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
- error_setg(errp, QERR_UNDEFINED_ERROR);
+ switch (addr->type) {
+ case SOCKET_ADDRESS_KIND_INET:
+ info->host = g_strdup(addr->u.inet->host);
+ info->service = g_strdup(addr->u.inet->port);
+ if (addr->u.inet->ipv6) {
+ info->family = NETWORK_ADDRESS_FAMILY_IPV6;
+ } else {
+ info->family = NETWORK_ADDRESS_FAMILY_IPV4;
+ }
+ break;
+
+ case SOCKET_ADDRESS_KIND_UNIX:
+ info->host = g_strdup("");
+ info->service = g_strdup(addr->u.q_unix->path);
+ info->family = NETWORK_ADDRESS_FAMILY_UNIX;
+ break;
+
+ default:
+ error_setg(errp, "Unsupported socket kind %d",
+ addr->type);
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));
}
+ qapi_free_SocketAddress(addr);
return info;
out_error:
+ qapi_free_SocketAddress(addr);
qapi_free_VncInfo(info);
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) {
+ Error *err = NULL;
+ SocketAddress *addr;
+
+ addr = qio_channel_socket_get_local_address(ioc, &err);
+ if (!addr) {
+ error_free(err);
return prev;
}
info = g_new0(VncBasicInfo, 1);
- info->host = g_strdup(host);
- info->service = g_strdup(serv);
- info->family = inet_netfamily(sa.ss_family);
+ vnc_init_basic_info(addr, info, &err);
+ qapi_free_SocketAddress(addr);
+ if (err) {
+ qapi_free_VncBasicInfo(info);
+ error_free(err);
+ return prev;
+ }
info->websocket = websocket;
list = g_new0(VncBasicInfoList, 1);
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);
static void vnc_refresh(DisplayChangeListener *dcl);
static int vnc_refresh_server_surface(VncDisplay *vd);
+static int vnc_width(VncDisplay *vd)
+{
+ return MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
+ VNC_DIRTY_PIXELS_PER_BIT));
+}
+
+static int vnc_height(VncDisplay *vd)
+{
+ return MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
+}
+
static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT),
- int width, int height,
- int x, int y, int w, int h) {
+ VncDisplay *vd,
+ int x, int y, int w, int h)
+{
+ int width = vnc_width(vd);
+ int height = vnc_height(vd);
+
/* this is needed this to ensure we updated all affected
* blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
w += (x % VNC_DIRTY_PIXELS_PER_BIT);
{
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
struct VncSurface *s = &vd->guest;
- int width = pixman_image_get_width(vd->server);
- int height = pixman_image_get_height(vd->server);
- vnc_set_area_dirty(s->dirty, width, height, x, y, w, h);
+ vnc_set_area_dirty(s->dirty, vd, x, y, w, h);
}
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
vnc_write_s32(vs, encoding);
}
-void buffer_reserve(Buffer *buffer, size_t len)
-{
- if ((buffer->capacity - buffer->offset) < len) {
- buffer->capacity += (len + 1024);
- buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
- }
-}
-
-static int buffer_empty(Buffer *buffer)
-{
- return buffer->offset == 0;
-}
-
-uint8_t *buffer_end(Buffer *buffer)
-{
- return buffer->buffer + buffer->offset;
-}
-
-void buffer_reset(Buffer *buffer)
-{
- buffer->offset = 0;
-}
-
-void buffer_free(Buffer *buffer)
-{
- g_free(buffer->buffer);
- buffer->offset = 0;
- buffer->capacity = 0;
- buffer->buffer = NULL;
-}
-
-void buffer_append(Buffer *buffer, const void *data, size_t len)
-{
- memcpy(buffer->buffer + buffer->offset, data, len);
- buffer->offset += len;
-}
-
-void buffer_advance(Buffer *buf, size_t len)
-{
- memmove(buf->buffer, buf->buffer + len,
- (buf->offset - len));
- buf->offset -= len;
-}
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) &&
return ptr;
}
+static void vnc_update_server_surface(VncDisplay *vd)
+{
+ qemu_pixman_image_unref(vd->server);
+ vd->server = NULL;
+
+ if (QTAILQ_EMPTY(&vd->clients)) {
+ return;
+ }
+
+ vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
+ vnc_width(vd),
+ vnc_height(vd),
+ NULL, 0);
+}
+
static void vnc_dpy_switch(DisplayChangeListener *dcl,
DisplaySurface *surface)
{
int width, height;
vnc_abort_display_jobs(vd);
+ vd->ds = surface;
/* server surface */
- qemu_pixman_image_unref(vd->server);
- vd->ds = surface;
- width = MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
- VNC_DIRTY_PIXELS_PER_BIT));
- height = MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
- vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
- width, height, NULL, 0);
+ vnc_update_server_surface(vd);
/* guest surface */
-#if 0 /* FIXME */
- if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
- console_color_init(ds);
-#endif
qemu_pixman_image_unref(vd->guest.fb);
vd->guest.fb = pixman_image_ref(surface->image);
vd->guest.format = surface->format;
+ width = vnc_width(vd);
+ height = vnc_height(vd);
memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty));
- vnc_set_area_dirty(vd->guest.dirty, width, height, 0, 0,
+ vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0,
width, height);
QTAILQ_FOREACH(vs, &vd->clients, next) {
vnc_cursor_define(vs);
}
memset(vs->dirty, 0x00, sizeof(vs->dirty));
- vnc_set_area_dirty(vs->dirty, width, height, 0, 0,
+ vnc_set_area_dirty(vs->dirty, vd, 0, 0,
width, height);
}
}
int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
{
int n = 0;
+ bool encode_raw = false;
+ size_t saved_offs = vs->output.offset;
switch(vs->vnc_encoding) {
case VNC_ENCODING_ZLIB:
n = vnc_zywrle_send_framebuffer_update(vs, x, y, w, h);
break;
default:
- vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
- n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+ encode_raw = true;
break;
}
+
+ /* If the client has the same pixel format as our internal buffer and
+ * a RAW encoding would need less space fall back to RAW encoding to
+ * save bandwidth and processing power in the client. */
+ if (!encode_raw && vs->write_pixels == vnc_write_pixels_copy &&
+ 12 + h * w * VNC_SERVER_FB_BYTES <= (vs->output.offset - saved_offs)) {
+ vs->output.offset = saved_offs;
+ encode_raw = true;
+ }
+
+ if (encode_raw) {
+ vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
+ n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+ }
+
return n;
}
int i, x, y, pitch, inc, w_lim, s;
int cmp_bytes;
+ if (!vd->server) {
+ /* no client connected */
+ return;
+ }
+
vnc_refresh_server_surface(vd);
QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
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;
return n;
}
- if (vs->csock == -1) {
+ if (vs->disconnecting) {
vnc_disconnect_finish(vs);
} else if (sync) {
vnc_jobs_join(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_handler(vs->csock, 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)
buffer_free(&vs->input);
buffer_free(&vs->output);
- buffer_free(&vs->ws_input);
- buffer_free(&vs->ws_output);
qapi_free_VncClientInfo(vs->info);
vnc_tight_clear(vs);
vnc_zrle_clear(vs);
- qcrypto_tls_session_free(vs->tls);
#ifdef CONFIG_VNC_SASL
vnc_sasl_client_cleanup(vs);
#endif /* CONFIG_VNC_SASL */
if (vs->initialized) {
QTAILQ_REMOVE(&vs->vd->clients, vs, next);
qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
+ if (QTAILQ_EMPTY(&vs->vd->clients)) {
+ /* last client gone */
+ vnc_update_server_surface(vs->vd);
+ }
}
if (vs->vd->lock_key_sync)
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);
}
-ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, int last_errno)
+ssize_t vnc_client_io_error(VncState *vs, ssize_t 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 %zd, errno %d\n",
- ret, ret < 0 ? last_errno : 0);
vnc_disconnect_start(vs);
-
+ if (errp) {
+ error_free(*errp);
+ *errp = NULL;
+ }
return 0;
}
return ret;
}
-ssize_t vnc_tls_pull(char *buf, size_t len, void *opaque)
-{
- VncState *vs = opaque;
- ssize_t ret;
-
- retry:
- ret = qemu_recv(vs->csock, buf, len, 0);
- if (ret < 0) {
- if (errno == EINTR) {
- goto retry;
- }
- return -1;
- }
- return ret;
-}
-
-
-ssize_t vnc_tls_push(const char *buf, size_t len, void *opaque)
-{
- VncState *vs = opaque;
- ssize_t ret;
-
- retry:
- ret = send(vs->csock, buf, len, 0);
- if (ret < 0) {
- if (errno == EINTR) {
- goto retry;
- }
- return -1;
- }
- return ret;
-}
-
-
/*
* Called to write a chunk of data to the client socket. The data may
* be the raw data, or may have already been encoded by SASL.
*/
ssize_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
{
+ Error *err = NULL;
ssize_t ret;
- int err = 0;
- if (vs->tls) {
- ret = qcrypto_tls_session_write(vs->tls, (const char *)data, datalen);
- if (ret < 0) {
- err = errno;
- }
- } else {
- ret = send(vs->csock, (const void *)data, datalen, 0);
- if (ret < 0) {
- err = socket_error();
- }
- }
+ ret = qio_channel_write(
+ vs->ioc, (const char *)data, datalen, &err);
VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
- return vnc_client_io_error(vs, ret, err);
+ return vnc_client_io_error(vs, ret, &err);
}
buffer_advance(&vs->output, ret);
if (vs->output.offset == 0) {
- qemu_set_fd_handler(vs->csock, 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, NULL);
}
return ret;
* 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 &&
} else
#endif /* CONFIG_VNC_SASL */
{
- if (vs->encode_ws) {
- vnc_client_write_ws(vs);
- } else {
- vnc_client_write_plain(vs);
- }
+ vnc_client_write_plain(vs);
}
}
-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_handler(vs->csock, vnc_client_read, NULL, vs);
+ if (vs->output.offset) {
+ 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, NULL);
}
vnc_unlock_output(vs);
}
ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
{
ssize_t ret;
- int err = -1;
- if (vs->tls) {
- ret = qcrypto_tls_session_read(vs->tls, (char *)data, datalen);
- if (ret < 0) {
- err = errno;
- }
- } else {
- ret = qemu_recv(vs->csock, data, datalen, 0);
- if (ret < 0) {
- err = socket_error();
- }
- }
+ Error *err = NULL;
+ ret = qio_channel_read(
+ vs->ioc, (char *)data, datalen, &err);
VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
- return vnc_client_io_error(vs, ret, err);
+ return vnc_client_io_error(vs, ret, &err);
}
* 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;
ssize_t ret;
#ifdef CONFIG_VNC_SASL
ret = vnc_client_read_sasl(vs);
else
#endif /* CONFIG_VNC_SASL */
- if (vs->encode_ws) {
- ret = vnc_client_read_ws(vs);
- if (ret == -1) {
- vnc_disconnect_start(vs);
- return;
- } else if (ret == -2) {
- vnc_client_error(vs);
- return;
- }
- } else {
- ret = vnc_client_read_plain(vs);
- }
+ ret = vnc_client_read_plain(vs);
if (!ret) {
- if (vs->csock == -1)
+ if (vs->disconnecting) {
vnc_disconnect_finish(vs);
+ }
return;
}
int ret;
ret = vs->read_handler(vs, vs->input.buffer, len);
- if (vs->csock == -1) {
+ if (vs->disconnecting) {
vnc_disconnect_finish(vs);
return;
}
}
}
+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)
{
buffer_reserve(&vs->output, len);
- if (vs->csock != -1 && buffer_empty(&vs->output)) {
- qemu_set_fd_handler(vs->csock, vnc_client_read, vnc_client_write, vs);
+ if (vs->ioc != NULL && 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, NULL);
}
buffer_append(&vs->output, data, len);
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) {
vnc_client_write_locked(vs);
}
vnc_unlock_output(vs);
static void pointer_event(VncState *vs, int button_mask, int x, int y)
{
- static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ static uint32_t bmap[INPUT_BUTTON__MAX] = {
[INPUT_BUTTON_LEFT] = 0x01,
[INPUT_BUTTON_MIDDLE] = 0x02,
[INPUT_BUTTON_RIGHT] = 0x04,
static void framebuffer_update_request(VncState *vs, int incremental,
int x, int y, int w, int h)
{
- int width = pixman_image_get_width(vs->vd->server);
- int height = pixman_image_get_height(vs->vd->server);
-
vs->need_update = 1;
if (incremental) {
}
vs->force_update = 1;
- vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h);
+ vnc_set_area_dirty(vs->dirty, vs->vd, x, y, w, h);
}
static void send_ext_key_event_ack(VncState *vs)
break;
case VNC_ENCODING_RICH_CURSOR:
vs->features |= VNC_FEATURE_RICH_CURSOR_MASK;
+ if (vs->vd->cursor) {
+ vnc_cursor_define(vs);
+ }
break;
case VNC_ENCODING_EXT_KEY_EVENT:
send_ext_key_event_ack(vs);
return;
}
- vs->client_pf.rmax = red_max;
+ vs->client_pf.rmax = red_max ? red_max : 0xFF;
vs->client_pf.rbits = hweight_long(red_max);
vs->client_pf.rshift = red_shift;
vs->client_pf.rmask = red_max << red_shift;
- vs->client_pf.gmax = green_max;
+ vs->client_pf.gmax = green_max ? green_max : 0xFF;
vs->client_pf.gbits = hweight_long(green_max);
vs->client_pf.gshift = green_shift;
vs->client_pf.gmask = green_max << green_shift;
- vs->client_pf.bmax = blue_max;
+ vs->client_pf.bmax = blue_max ? blue_max : 0xFF;
vs->client_pf.bbits = hweight_long(blue_max);
vs->client_pf.bshift = blue_shift;
vs->client_pf.bmask = blue_max << blue_shift;
}
}
-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));
+ VncState *vs = g_new0(VncState, 1);
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;
+ buffer_init(&vs->input, "vnc-input/%p", sioc);
+ buffer_init(&vs->output, "vnc-output/%p", sioc);
+ buffer_init(&vs->jobs_buffer, "vnc-jobs_buffer/%p", sioc);
+
+ buffer_init(&vs->tight.tight, "vnc-tight/%p", sioc);
+ buffer_init(&vs->tight.zlib, "vnc-tight-zlib/%p", sioc);
+ buffer_init(&vs->tight.gradient, "vnc-tight-gradient/%p", sioc);
+#ifdef CONFIG_VNC_JPEG
+ buffer_init(&vs->tight.jpeg, "vnc-tight-jpeg/%p", sioc);
+#endif
+#ifdef CONFIG_VNC_PNG
+ buffer_init(&vs->tight.png, "vnc-tight-png/%p", sioc);
+#endif
+ buffer_init(&vs->zlib.zlib, "vnc-zlib/%p", sioc);
+ buffer_init(&vs->zrle.zrle, "vnc-zrle/%p", sioc);
+ buffer_init(&vs->zrle.fb, "vnc-zrle-fb/%p", sioc);
+ buffer_init(&vs->zrle.zlib, "vnc-zrle-zlib/%p", sioc);
+
if (skipauth) {
vs->auth = VNC_AUTH_NONE;
vs->subauth = VNC_AUTH_INVALID;
vs->subauth = vd->subauth;
}
}
- VNC_DEBUG("Client sock=%d ws=%d auth=%d subauth=%d\n",
- csock, websocket, vs->auth, vs->subauth);
+ VNC_DEBUG("Client sioc=%p ws=%d auth=%d subauth=%d\n",
+ sioc, websocket, vs->auth, vs->subauth);
vs->lossy_rect = g_malloc0(VNC_STAT_ROWS * sizeof (*vs->lossy_rect));
for (i = 0; i < VNC_STAT_ROWS; ++i) {
- vs->lossy_rect[i] = g_malloc0(VNC_STAT_COLS * sizeof (uint8_t));
+ vs->lossy_rect[i] = g_new0(uint8_t, VNC_STAT_COLS);
}
- 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, NULL);
if (websocket) {
vs->websocket = 1;
if (vd->ws_tls) {
- qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, NULL, vs);
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vncws_tls_handshake_io, vs, NULL);
} else {
- qemu_set_fd_handler(vs->csock, vncws_handshake_read, NULL, vs);
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vncws_handshake_io, vs, NULL);
}
- } else
- {
- qemu_set_fd_handler(vs->csock, vnc_client_read, NULL, vs);
+ } else {
+ vs->ioc_tag = qio_channel_add_watch(
+ vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
}
vnc_client_cache_addr(vs);
{
vs->initialized = true;
VncDisplay *vd = vs->vd;
+ bool first_client = QTAILQ_EMPTY(&vd->clients);
vs->last_x = -1;
vs->last_y = -1;
vs->bh = qemu_bh_new(vnc_jobs_bh, vs);
QTAILQ_INSERT_TAIL(&vd->clients, vs, next);
+ if (first_client) {
+ vnc_update_server_surface(vd);
+ }
graphic_hw_update(vd->dcl.con);
/* 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_set_delay(QIO_CHANNEL(sioc), false);
+ 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 = {
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;
return;
vs->enabled = false;
vs->is_unix = false;
- if (vs->lsock != -1) {
- qemu_set_fd_handler(vs->lsock, 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_handler(vs->lwebsock, 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;
if (vs->tlscreds) {
object_unparent(OBJECT(vs->tlscreds));
+ vs->tlscreds = NULL;
}
g_free(vs->tlsaclname);
vs->tlsaclname = NULL;
char *vnc_display_local_addr(const char *id)
{
VncDisplay *vs = vnc_display_find(id);
+ SocketAddress *addr;
+ char *ret;
+ Error *err = NULL;
assert(vs);
- return vnc_socket_local_addr("%s:%s", vs->lsock);
+
+ addr = qio_channel_socket_get_local_address(vs->lsock, &err);
+ if (!addr) {
+ return NULL;
+ }
+
+ if (addr->type != SOCKET_ADDRESS_KIND_INET) {
+ qapi_free_SocketAddress(addr);
+ return NULL;
+ }
+ ret = g_strdup_printf("%s;%s", addr->u.inet->host, addr->u.inet->port);
+ qapi_free_SocketAddress(addr);
+
+ return ret;
}
static QemuOptsList qemu_vnc_opts = {
{
VncDisplay *vs = vnc_display_find(id);
QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
- QemuOpts *sopts, *wsopts;
+ SocketAddress *saddr = NULL, *wsaddr = NULL;
const char *share, *device_id;
QemuConsole *con;
bool password = false;
bool reverse = false;
const char *vnc;
- const char *has_to;
char *h;
- bool has_ipv4 = false;
- bool has_ipv6 = false;
const char *credid;
- const char *websocket;
bool sasl = false;
#ifdef CONFIG_VNC_SASL
int saslErr;
return;
}
- sopts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
- wsopts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
-
h = strrchr(vnc, ':');
if (h) {
- char *host;
size_t hlen = h - vnc;
- if (vnc[0] == '[' && vnc[hlen - 1] == ']') {
- host = g_strndup(vnc + 1, hlen - 2);
+ const char *websocket = qemu_opt_get(opts, "websocket");
+ int to = qemu_opt_get_number(opts, "to", 0);
+ bool has_ipv4 = qemu_opt_get(opts, "ipv4");
+ bool has_ipv6 = qemu_opt_get(opts, "ipv6");
+ bool ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
+ bool ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
+
+ saddr = g_new0(SocketAddress, 1);
+ if (websocket) {
+ if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
+ error_setg(errp,
+ "SHA1 hash support is required for websockets");
+ goto fail;
+ }
+
+ wsaddr = g_new0(SocketAddress, 1);
+ vs->ws_enabled = true;
+ }
+
+ if (strncmp(vnc, "unix:", 5) == 0) {
+ saddr->type = SOCKET_ADDRESS_KIND_UNIX;
+ saddr->u.q_unix = g_new0(UnixSocketAddress, 1);
+ saddr->u.q_unix->path = g_strdup(vnc + 5);
+
+ if (vs->ws_enabled) {
+ error_setg(errp, "UNIX sockets not supported with websock");
+ goto fail;
+ }
} else {
- host = g_strndup(vnc, hlen);
+ unsigned long long baseport;
+ InetSocketAddress *inet;
+ saddr->type = SOCKET_ADDRESS_KIND_INET;
+ inet = saddr->u.inet = g_new0(InetSocketAddress, 1);
+ if (vnc[0] == '[' && vnc[hlen - 1] == ']') {
+ inet->host = g_strndup(vnc + 1, hlen - 2);
+ } else {
+ inet->host = g_strndup(vnc, hlen);
+ }
+ if (parse_uint_full(h + 1, &baseport, 10) < 0) {
+ error_setg(errp, "can't convert to a number: %s", h + 1);
+ goto fail;
+ }
+ if (baseport > 65535 ||
+ baseport + 5900 > 65535) {
+ error_setg(errp, "port %s out of range", h + 1);
+ goto fail;
+ }
+ inet->port = g_strdup_printf(
+ "%d", (int)baseport + 5900);
+
+ if (to) {
+ inet->has_to = true;
+ inet->to = to + 5900;
+ }
+ inet->ipv4 = ipv4;
+ inet->has_ipv4 = has_ipv4;
+ inet->ipv6 = ipv6;
+ inet->has_ipv6 = has_ipv6;
+
+ if (vs->ws_enabled) {
+ wsaddr->type = SOCKET_ADDRESS_KIND_INET;
+ inet = wsaddr->u.inet = g_new0(InetSocketAddress, 1);
+ inet->host = g_strdup(saddr->u.inet->host);
+ inet->port = g_strdup(websocket);
+
+ if (to) {
+ inet->has_to = true;
+ inet->to = to;
+ }
+ inet->ipv4 = ipv4;
+ inet->has_ipv4 = has_ipv4;
+ inet->ipv6 = ipv6;
+ inet->has_ipv6 = has_ipv6;
+ }
}
- qemu_opt_set(sopts, "host", host, &error_abort);
- qemu_opt_set(wsopts, "host", host, &error_abort);
- qemu_opt_set(sopts, "port", h+1, &error_abort);
- g_free(host);
} else {
error_setg(errp, "no vnc port specified");
goto fail;
}
- has_to = qemu_opt_get(opts, "to");
- has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
- has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
- if (has_to) {
- qemu_opt_set(sopts, "to", has_to, &error_abort);
- qemu_opt_set(wsopts, "to", has_to, &error_abort);
- }
- if (has_ipv4) {
- qemu_opt_set(sopts, "ipv4", "on", &error_abort);
- qemu_opt_set(wsopts, "ipv4", "on", &error_abort);
- }
- if (has_ipv6) {
- qemu_opt_set(sopts, "ipv6", "on", &error_abort);
- qemu_opt_set(wsopts, "ipv6", "on", &error_abort);
- }
-
password = qemu_opt_get_bool(opts, "password", false);
if (password) {
if (fips_get_state()) {
qemu_opt_get(opts, "x509") ||
qemu_opt_get(opts, "x509verify")) {
error_setg(errp,
- "'credid' parameter is mutually exclusive with "
+ "'tls-creds' parameter is mutually exclusive with "
"'tls', 'x509' and 'x509verify' parameters");
goto fail;
}
}
vs->connections_limit = qemu_opt_get_number(opts, "connections", 32);
- websocket = qemu_opt_get(opts, "websocket");
- if (websocket) {
- vs->ws_enabled = true;
- qemu_opt_set(wsopts, "port", websocket, &error_abort);
- if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
- error_setg(errp, "SHA1 hash support is required for websockets");
- goto fail;
- }
- }
-
#ifdef CONFIG_VNC_JPEG
vs->lossy = qemu_opt_get_bool(opts, "lossy", false);
#endif
vs->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vs->id);
}
qemu_acl_init(vs->tlsaclname);
- }
+ }
#ifdef CONFIG_VNC_SASL
if (acl && sasl) {
char *aclname;
}
#endif
- if (vnc_display_setup_auth(vs, password, sasl, websocket, errp) < 0) {
+ if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) {
goto fail;
}
device_id = qemu_opt_get(opts, "display");
if (device_id) {
- DeviceState *dev;
int head = qemu_opt_get_number(opts, "head", 0);
+ Error *err = NULL;
- dev = qdev_find_recursive(sysbus_get_default(), device_id);
- if (dev == NULL) {
- error_setg(errp, "Device '%s' not found", device_id);
- goto fail;
- }
-
- con = qemu_console_lookup_by_device(dev, head);
- if (con == NULL) {
- error_setg(errp, "Device %s is not bound to a QemuConsole",
- device_id);
+ con = qemu_console_lookup_by_device_name(device_id, head, &err);
+ if (err) {
+ error_propagate(errp, err);
goto fail;
}
} else {
if (reverse) {
/* connect to viewer */
- int csock;
- vs->lsock = -1;
- vs->lwebsock = -1;
- if (strncmp(vnc, "unix:", 5) == 0) {
- csock = unix_connect(vnc+5, errp);
- } else {
- csock = inet_connect(vnc, errp);
+ QIOChannelSocket *sioc = NULL;
+ vs->lsock = NULL;
+ vs->lwebsock = NULL;
+ if (vs->ws_enabled) {
+ error_setg(errp, "Cannot use websockets in reverse mode");
+ goto fail;
}
- if (csock < 0) {
+ vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
+ sioc = qio_channel_socket_new();
+ if (qio_channel_socket_connect_sync(sioc, saddr, errp) < 0) {
goto fail;
}
- vnc_connect(vs, csock, false, false);
+ vnc_connect(vs, sioc, false, false);
+ object_unref(OBJECT(sioc));
} else {
- /* listen for connects */
- if (strncmp(vnc, "unix:", 5) == 0) {
- vs->lsock = unix_listen(vnc+5, NULL, 0, errp);
- if (vs->lsock < 0) {
- goto fail;
- }
- vs->is_unix = true;
- } else {
- vs->lsock = inet_listen_opts(sopts, 5900, errp);
- if (vs->lsock < 0) {
+ vs->lsock = qio_channel_socket_new();
+ if (qio_channel_socket_listen_sync(vs->lsock, saddr, errp) < 0) {
+ goto fail;
+ }
+ vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
+ vs->enabled = true;
+
+ if (vs->ws_enabled) {
+ vs->lwebsock = qio_channel_socket_new();
+ if (qio_channel_socket_listen_sync(vs->lwebsock,
+ wsaddr, errp) < 0) {
+ object_unref(OBJECT(vs->lsock));
+ vs->lsock = NULL;
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;
- }
- goto fail;
- }
- }
}
- vs->enabled = true;
- qemu_set_fd_handler(vs->lsock, vnc_listen_regular_read, NULL, vs);
+
+ vs->lsock_tag = qio_channel_add_watch(
+ QIO_CHANNEL(vs->lsock),
+ G_IO_IN, vnc_listen_io, vs, NULL);
if (vs->ws_enabled) {
- qemu_set_fd_handler(vs->lwebsock, vnc_listen_websocket_read,
- NULL, vs);
+ vs->lwebsock_tag = qio_channel_add_watch(
+ QIO_CHANNEL(vs->lwebsock),
+ G_IO_IN, vnc_listen_io, vs, NULL);
}
}
- qemu_opts_del(sopts);
- qemu_opts_del(wsopts);
+
+ qapi_free_SocketAddress(saddr);
+ qapi_free_SocketAddress(wsaddr);
return;
fail:
- qemu_opts_del(sopts);
- qemu_opts_del(wsopts);
+ qapi_free_SocketAddress(saddr);
+ qapi_free_SocketAddress(wsaddr);
vs->enabled = false;
vs->ws_enabled = false;
}
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)
vnc_display_init(id);
vnc_display_open(id, &local_err);
if (local_err != NULL) {
- error_report("Failed to start VNC server: %s",
- error_get_pretty(local_err));
- error_free(local_err);
+ error_reportf_err(local_err, "Failed to start VNC server: ");
exit(1);
}
return 0;
{
qemu_add_opts(&qemu_vnc_opts);
}
-machine_init(vnc_register_config);
+opts_init(vnc_register_config);