From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35826) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZXWcj-0004S5-Ve for qemu-devel@nongnu.org; Thu, 03 Sep 2015 11:40:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZXWcf-0007i6-SW for qemu-devel@nongnu.org; Thu, 03 Sep 2015 11:40:25 -0400 Received: from mx1.redhat.com ([209.132.183.28]:41080) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZXWcf-0007hy-Gg for qemu-devel@nongnu.org; Thu, 03 Sep 2015 11:40:21 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id 3A670A3813 for ; Thu, 3 Sep 2015 15:40:21 +0000 (UTC) From: "Daniel P. Berrange" Date: Thu, 3 Sep 2015 16:38:58 +0100 Message-Id: <1441294768-8712-17-git-send-email-berrange@redhat.com> In-Reply-To: <1441294768-8712-1-git-send-email-berrange@redhat.com> References: <1441294768-8712-1-git-send-email-berrange@redhat.com> Subject: [Qemu-devel] [PATCH FYI 16/46] ui: convert VNC server to use QIOChannelSocket List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Juan Quintela , "Dr. David Alan Gilbert" , Gerd Hoffmann , Amit Shah , Paolo Bonzini The minimal first step conversion to use QIOChannelSocket 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 --- ui/vnc-auth-sasl.c | 57 +++-- ui/vnc-auth-vencrypt.c | 27 ++- ui/vnc-jobs.c | 12 +- ui/vnc-ws.c | 51 ++++- ui/vnc-ws.h | 8 +- ui/vnc.c | 559 ++++++++++++++++++++++++++----------------------- ui/vnc.h | 22 +- 7 files changed, 426 insertions(+), 310 deletions(-) diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c index d118266..f5bfdd1 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_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; @@ -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); } @@ -487,6 +491,32 @@ static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, s return 0; } +static char * +vnc_socket_ip_addr_string(QIOChannelSocket *ioc, + bool local, + Error **errp) +{ + SocketAddress *addr; + char *ret; + + if (local) { + addr = qio_channel_socket_get_local_address(ioc, errp); + } else { + addr = qio_channel_socket_get_remote_address(ioc, errp); + } + if (!addr) { + return NULL; + } + + if (addr->kind != SOCKET_ADDRESS_KIND_INET) { + error_setg(errp, "Not an inet socket type"); + return NULL; + } + ret = g_strdup_printf("%s;%s", addr->inet->host, addr->inet->port); + qapi_free_SocketAddress(addr); + return ret; +} + void start_auth_sasl(VncState *vs) { const char *mechlist = NULL; @@ -495,13 +525,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_ip_addr_string(vs->sioc, true, NULL); + if (!localAddr) { goto authabort; + } - if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) { + remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, NULL); + if (!remoteAddr) { g_free(localAddr); goto authabort; } diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c index 44ac2fa..95a6823 100644 --- a/ui/vnc-auth-vencrypt.c +++ b/ui/vnc-auth-vencrypt.c @@ -63,7 +63,9 @@ 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(VncState *vs) { @@ -80,19 +82,31 @@ static int vnc_start_vencrypt_handshake(VncState *vs) goto error; } VNC_DEBUG("Client verification passed, starting TLS I/O\n"); - qemu_set_fd_handler(vs->csock, 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, NULL); start_auth_vencrypt_subauth(vs); break; case QCRYPTO_TLS_HANDSHAKE_RECVING: VNC_DEBUG("Handshake interrupted (blocking read)\n"); - qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, 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_tls_handshake_io, vs, NULL); break; case QCRYPTO_TLS_HANDSHAKE_SENDING: VNC_DEBUG("Handshake interrupted (blocking write)\n"); - qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs); + if (vs->ioc_tag) { + g_source_remove(vs->ioc_tag); + } + vs->ioc_tag = qio_channel_add_watch( + vs->ioc, G_IO_OUT, vnc_tls_handshake_io, vs, NULL); break; } @@ -105,12 +119,15 @@ static int vnc_start_vencrypt_handshake(VncState *vs) return -1; } -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) { VncState *vs = (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 9824c34..7c44e5b 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -169,7 +169,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) { @@ -194,7 +194,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); } @@ -231,7 +232,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; } @@ -251,7 +252,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); @@ -273,8 +274,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-ws.c b/ui/vnc-ws.c index 2fe4476..7b2cc68 100644 --- a/ui/vnc-ws.c +++ b/ui/vnc-ws.c @@ -37,17 +37,29 @@ static int vncws_start_tls_handshake(VncState *vs) goto error; } VNC_DEBUG("Client verification passed, starting TLS I/O\n"); - qemu_set_fd_handler(vs->csock, 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, NULL); break; case QCRYPTO_TLS_HANDSHAKE_RECVING: VNC_DEBUG("Handshake interrupted (blocking read)\n"); - qemu_set_fd_handler(vs->csock, vncws_tls_handshake_io, 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_tls_handshake_io, vs, NULL); break; case QCRYPTO_TLS_HANDSHAKE_SENDING: VNC_DEBUG("Handshake interrupted (blocking write)\n"); - qemu_set_fd_handler(vs->csock, NULL, vncws_tls_handshake_io, vs); + if (vs->ioc_tag) { + g_source_remove(vs->ioc_tag); + } + vs->ioc_tag = qio_channel_add_watch( + vs->ioc, G_IO_OUT, vncws_tls_handshake_io, vs, NULL); break; } @@ -60,7 +72,9 @@ static int vncws_start_tls_handshake(VncState *vs) return -1; } -void vncws_tls_handshake_io(void *opaque) +gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED, + GIOCondition condition G_GNUC_UNUSED, + void *opaque) { VncState *vs = (VncState *)opaque; Error *err = NULL; @@ -75,7 +89,7 @@ void vncws_tls_handshake_io(void *opaque) error_get_pretty(err)); error_free(err); vnc_client_error(vs); - return; + return TRUE; } qcrypto_tls_session_set_callbacks(vs->tls, @@ -85,11 +99,11 @@ void vncws_tls_handshake_io(void *opaque) VNC_DEBUG("Start TLS WS handshake process\n"); vncws_start_tls_handshake(vs); + return TRUE; } -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 @@ -99,7 +113,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; @@ -109,7 +123,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_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); 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)); @@ -120,6 +138,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; @@ -187,7 +214,11 @@ long vnc_client_write_ws(VncState *vs) qio_buffer_advance(&vs->ws_output, ret); if (vs->ws_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; diff --git a/ui/vnc-ws.h b/ui/vnc-ws.h index 2a222a8..21caaf3 100644 --- a/ui/vnc-ws.h +++ b/ui/vnc-ws.h @@ -72,8 +72,12 @@ enum { WS_OPCODE_PONG = 0xA }; -void vncws_tls_handshake_io(void *opaque); -void vncws_handshake_read(void *opaque); +gboolean vncws_tls_handshake_io(QIOChannel *ioc, + GIOCondition condition, + 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 8896fef..2f8c15e 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -70,8 +70,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) { @@ -105,105 +105,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); -} +static VncBasicInfo * +vnc_basic_info_from_socket_address(SocketAddress *addr, + Error **errp) +{ + VncBasicInfo *info; -char *vnc_socket_remote_addr(const char *format, int fd) { - struct sockaddr_storage sa; - socklen_t salen; + info = g_new0(VncBasicInfo, 1); - salen = sizeof(sa); - if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) - return NULL; + switch (addr->kind) { + case SOCKET_ADDRESS_KIND_INET: + info->host = g_strdup(addr->inet->host); + info->service = g_strdup(addr->inet->port); + if (addr->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->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)); + default: + error_setg(errp, "Unsupported socket kind %d", + addr->kind); + g_free(info); 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; } -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; + SocketAddress *addr; - salen = sizeof(sa); - if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) { + addr = qio_channel_socket_get_local_address(ioc, errp); + if (!addr) { return NULL; } - return vnc_basic_info_get(&sa, salen); + info = vnc_basic_info_from_socket_address(addr, errp); + qapi_free_SocketAddress(addr); + 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; + SocketAddress *addr; - salen = sizeof(sa); - if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) { + addr = qio_channel_socket_get_remote_address(ioc, errp); + if (!addr) { return NULL; } - return vnc_basic_info_get(&sa, salen); + info = vnc_basic_info_from_socket_address(addr, errp); + qapi_free_SocketAddress(addr); + return info; } static const char *vnc_auth_name(VncDisplay *vd) { @@ -256,8 +225,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 +263,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 +308,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; if (client->tls) { @@ -403,81 +370,86 @@ VncInfo *qmp_query_vnc(Error **errp) { 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->kind) { + case SOCKET_ADDRESS_KIND_INET: + info->host = g_strdup(addr->inet->host); + info->service = g_strdup(addr->inet->port); + if (addr->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->q_unix->path); + info->family = NETWORK_ADDRESS_FAMILY_UNIX; + break; + + default: + error_setg(errp, "Unsupported socket kind %d", + addr->kind); 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 = vnc_basic_info_from_socket_address(addr, &err); + qapi_free_SocketAddress(addr); + if (!info) { + 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); info->websocket = websocket; list = g_new0(VncBasicInfoList, 1); @@ -571,13 +543,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); @@ -650,7 +622,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) && @@ -1014,7 +986,7 @@ static int find_and_clear_dirty_height(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; @@ -1078,7 +1050,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); @@ -1160,12 +1132,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_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) @@ -1214,29 +1189,29 @@ 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); } -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; @@ -1253,13 +1228,12 @@ void vnc_client_error(VncState *vs) 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); + ssize_t ret = qio_channel_read(vs->ioc, buf, len, NULL); if (ret < 0) { - if (errno == EINTR) { - goto retry; + if (ret == QIO_CHANNEL_ERR_BLOCK) { + errno = EAGAIN; + } else { + errno = EIO; } return -1; } @@ -1270,13 +1244,12 @@ ssize_t vnc_tls_pull(char *buf, size_t len, void *opaque) 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); + ssize_t ret = qio_channel_write(vs->ioc, buf, len, NULL); if (ret < 0) { - if (errno == EINTR) { - goto retry; + if (ret == QIO_CHANNEL_ERR_BLOCK) { + errno = EAGAIN; + } else { + errno = EIO; } return -1; } @@ -1301,21 +1274,25 @@ ssize_t vnc_tls_push(const char *buf, size_t len, void *opaque) */ 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; + if (errno == EAGAIN) { + ret = QIO_CHANNEL_ERR_BLOCK; + } else { + ret = -1; + error_setg_errno(&err, errno, "%s", + "Cannot write to TLS socket"); + } } } 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); } @@ -1353,7 +1330,11 @@ static ssize_t vnc_client_write_plain(VncState *vs) qio_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; @@ -1365,10 +1346,8 @@ static ssize_t 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 && @@ -1385,15 +1364,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_handler(vs->csock, 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, NULL); } vnc_unlock_output(vs); } @@ -1423,20 +1405,24 @@ void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) ssize_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen) { ssize_t ret; - int err = -1; + Error *err = NULL; if (vs->tls) { ret = qcrypto_tls_session_read(vs->tls, (char *)data, datalen); if (ret < 0) { - err = errno; + if (errno == EAGAIN) { + ret = QIO_CHANNEL_ERR_BLOCK; + } else { + ret = -1; + error_setg_errno(&err, errno, "%s", + "Cannot read from TLS socket"); + } } } else { - ret = qemu_recv(vs->csock, data, datalen, 0); - if (ret < 0) { - err = socket_error(); - } + 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); } @@ -1473,9 +1459,8 @@ 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; ssize_t ret; #ifdef CONFIG_VNC_SASL @@ -1496,8 +1481,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; } @@ -1506,7 +1492,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; } @@ -1519,12 +1505,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_handler(vs->csock, 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, NULL); } qio_buffer_append(&vs->output, data, len); @@ -1565,8 +1569,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); @@ -2953,13 +2956,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) { @@ -2982,19 +2988,21 @@ 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; 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); @@ -3048,35 +3056,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); - } - - if (csock != -1) { - socket_set_nodelay(csock); - vnc_connect(vs, csock, false, websocket); + /* client probably closed connection before we got there */ + error_free(err); } -} - -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 = { @@ -3102,9 +3103,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; @@ -3132,16 +3130,20 @@ static void vnc_display_close(VncDisplay *vs) 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; @@ -3186,9 +3188,25 @@ int vnc_display_pw_expire(const char *id, time_t expires) 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->kind != SOCKET_ADDRESS_KIND_INET) { + qapi_free_SocketAddress(addr); + return NULL; + } + ret = g_strdup_printf("%s;%s", addr->inet->host, addr->inet->port); + qapi_free_SocketAddress(addr); + + return ret; } static QemuOptsList qemu_vnc_opts = { @@ -3749,42 +3767,45 @@ 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 (vs->ws_enabled) { error_setg(errp, "Cannot use websockets in reverse mode"); goto fail; } - csock = socket_connect(saddr, errp, - NULL, NULL); - if (csock < 0) { + vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX; + sioc = qio_channel_socket_new(); + if (qio_channel_socket_connect_sync(sioc, saddr, errp) < 0) { goto fail; } - vs->is_unix = saddr->kind == SOCKET_ADDRESS_KIND_UNIX; - vnc_connect(vs, csock, false, false); + vnc_connect(vs, sioc, false, false); + object_unref(OBJECT(sioc)); } else { - /* listen for connects */ - vs->lsock = socket_listen(saddr, 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->kind == SOCKET_ADDRESS_KIND_UNIX; + vs->enabled = true; + if (vs->ws_enabled) { - vs->lwebsock = socket_listen(wsaddr, errp); - if (vs->lwebsock < 0) { - if (vs->lsock != -1) { - close(vs->lsock); - vs->lsock = -1; - } + 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; } } - 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); } } @@ -3802,11 +3823,17 @@ fail: 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 339a1bf..e9b4a00 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -35,6 +35,7 @@ #include "qemu/bitmap.h" #include "crypto/tlssession.h" #include "io/buffer.h" +#include "io/channel-socket.h" #include #include @@ -145,8 +146,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; @@ -248,7 +251,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 @@ -499,8 +505,9 @@ 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); 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); @@ -524,7 +531,7 @@ uint32_t read_u32(uint8_t *data, size_t offset); /* Protocol stage functions */ void vnc_client_error(VncState *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); void start_client_init(VncState *vs); void start_auth_vnc(VncState *vs); @@ -532,9 +539,6 @@ 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); - static inline uint32_t vnc_has_feature(VncState *vs, int feature) { return (vs->features & (1 << feature)); } -- 2.4.3