提交 04d2529d 编写于 作者: D Daniel P. Berrange

ui: convert VNC server to use QIOChannelSocket

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.
Reviewed-by: NGerd Hoffmann <kraxel@redhat.com>
Signed-off-by: NDaniel P. Berrange <berrange@redhat.com>
上级 18f49881
......@@ -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);
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->type != SOCKET_ADDRESS_KIND_INET) {
error_setg(errp, "Not an inet socket type");
return NULL;
}
ret = g_strdup_printf("%s;%s", addr->u.inet->host, addr->u.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;
}
......
......@@ -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;
}
......
......@@ -166,13 +166,16 @@ void vnc_jobs_consume_buffer(VncState *vs)
vnc_lock_output(vs);
if (vs->jobs_buffer.offset) {
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_move(&vs->output, &vs->jobs_buffer);
}
flush = vs->csock != -1 && vs->abort != true;
flush = vs->ioc != NULL && vs->abort != true;
vnc_unlock_output(vs);
if (flush) {
......@@ -186,7 +189,8 @@ void vnc_jobs_consume_buffer(VncState *vs)
static void vnc_async_encoding_start(VncState *orig, VncState *local)
{
buffer_init(&local->output, "vnc-worker-output");
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 */
local->vnc_encoding = orig->vnc_encoding;
local->features = orig->features;
......@@ -231,7 +235,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;
}
......@@ -259,7 +263,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);
......@@ -281,7 +285,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) {
buffer_move(&job->vs->jobs_buffer, &vs.output);
/* Copy persistent encoding data */
vnc_async_encoding_end(job->vs, &vs);
......
......@@ -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, 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);
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)
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;
......
......@@ -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);
......
此差异已折叠。
......@@ -35,6 +35,7 @@
#include "qemu/bitmap.h"
#include "crypto/tlssession.h"
#include "qemu/buffer.h"
#include "io/channel-socket.h"
#include <zlib.h>
#include <stdbool.h>
......@@ -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));
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册