[gtk-vnc] Introduce a "vnc-error" signal
- From: Daniel P. Berrange <dberrange src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk-vnc] Introduce a "vnc-error" signal
- Date: Tue, 16 Aug 2016 09:13:19 +0000 (UTC)
commit 73bd11b94dfbe6fc4526beea7185f089538aa824
Author: Daniel P. Berrange <berrange redhat com>
Date: Mon Aug 15 13:10:59 2016 +0100
Introduce a "vnc-error" signal
Provide the app uing GTK-VNC with information about what caused
the error via a new "vnc-error" signal.
Resolves: bz#762223, #768237
Signed-off-by: Daniel P. Berrange <berrange redhat com>
examples/gvncviewer.c | 8 +
src/vncconnection.c | 440 ++++++++++++++++++++++++++++---------------------
src/vncconnection.h | 3 +-
src/vncdisplay.c | 25 +++
4 files changed, 283 insertions(+), 193 deletions(-)
---
diff --git a/examples/gvncviewer.c b/examples/gvncviewer.c
index 8a96709..2ec8e0e 100644
--- a/examples/gvncviewer.c
+++ b/examples/gvncviewer.c
@@ -239,6 +239,12 @@ static void vnc_connected(GtkWidget *vncdisplay G_GNUC_UNUSED)
connected = 1;
}
+static void vnc_error(GtkWidget *vncdisplay G_GNUC_UNUSED,
+ const gchar *message)
+{
+ fprintf(stderr, "Error: %s\n", message);
+}
+
static void vnc_initialized(GtkWidget *vncdisplay, GtkWidget *window)
{
printf("Connection initialized\n");
@@ -829,6 +835,8 @@ int main(int argc, char **argv)
G_CALLBACK(vnc_initialized), window);
g_signal_connect(vnc, "vnc-disconnected",
G_CALLBACK(vnc_disconnected), NULL);
+ g_signal_connect(vnc, "vnc-error",
+ G_CALLBACK(vnc_error), NULL);
g_signal_connect(vnc, "vnc-auth-credential",
G_CALLBACK(vnc_credential), NULL);
g_signal_connect(vnc, "vnc-auth-failure",
diff --git a/src/vncconnection.c b/src/vncconnection.c
index 3d6e77e..52dc6cb 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -152,6 +152,9 @@ typedef void vnc_connection_tight_compute_predicted_func(VncConnection *conn, gu
typedef void vnc_connection_tight_sum_pixel_func(VncConnection *conn, guint8 *, guint8 *);
static void vnc_connection_close(VncConnection *conn);
+static void vnc_connection_set_error(VncConnection *conn,
+ const char *format,
+ ...) G_GNUC_PRINTF(2, 3);
/*
* A special GSource impl which allows us to wait on a certain
@@ -186,7 +189,8 @@ struct _VncConnectionPrivate
char *host;
char *port;
VncPixelFormat fmt;
- gboolean has_error;
+ char *error;
+ gboolean coroutine_stop;
int width;
int height;
char *name;
@@ -296,6 +300,7 @@ enum {
VNC_CONNECTED,
VNC_INITIALIZED,
VNC_DISCONNECTED,
+ VNC_ERROR,
VNC_LAST_SIGNAL,
};
@@ -308,6 +313,7 @@ static guint signals[VNC_LAST_SIGNAL] = { 0, 0, 0, 0,
#define nibhi(a) (((a) >> 4) & 0x0F)
#define niblo(a) ((a) & 0x0F)
+
/* Main loop helper functions */
static gboolean g_io_wait_helper(GSocket *sock G_GNUC_UNUSED,
GIOCondition cond,
@@ -503,6 +509,7 @@ struct signal_data
unsigned int authUnsupported;
GValueArray *authCred;
GValueArray *authTypes;
+ const char *message;
} params;
};
@@ -615,6 +622,13 @@ static gboolean do_vnc_connection_emit_main_context(gpointer opaque)
0);
break;
+ case VNC_ERROR:
+ g_signal_emit(G_OBJECT(data->conn),
+ signals[data->signum],
+ 0,
+ data->params.message);
+ break;
+
default:
g_warn_if_reached();
}
@@ -644,6 +658,27 @@ static void vnc_connection_emit_main_context(VncConnection *conn,
}
+static G_GNUC_PRINTF(2, 3) void vnc_connection_set_error(VncConnection *conn,
+ const char *format,
+ ...)
+{
+ va_list args;
+ struct signal_data s;
+
+ va_start(args, format);
+
+ g_free(conn->priv->error);
+ conn->priv->error = g_strdup_vprintf(format, args);
+ va_end(args);
+ conn->priv->coroutine_stop = TRUE;
+
+ VNC_DEBUG("Error: %s", conn->priv->error);
+
+ s.params.message = conn->priv->error;
+ vnc_connection_emit_main_context(conn, VNC_ERROR, &s);
+}
+
+
static gboolean vnc_connection_use_compression(VncConnection *conn)
{
VncConnectionPrivate *priv = conn->priv;
@@ -710,7 +745,7 @@ static int vnc_connection_read_wire(VncConnection *conn, void *data, size_t len)
reread:
- if (priv->has_error) return -EINVAL;
+ if (priv->coroutine_stop) return -EINVAL;
if (priv->tls_session) {
ret = gnutls_read(priv->tls_session, data, len);
@@ -742,7 +777,6 @@ static int vnc_connection_read_wire(VncConnection *conn, void *data, size_t len)
if (priv->wait_interruptable) {
if (!g_io_wait_interruptable(&priv->wait,
priv->sock, G_IO_IN)) {
- //VNC_DEBUG("Read blocking interrupted %d", priv->has_error);
return -EAGAIN;
}
} else {
@@ -751,13 +785,13 @@ static int vnc_connection_read_wire(VncConnection *conn, void *data, size_t len)
blocking = FALSE;
goto reread;
} else {
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Unable to read from server");
return -errno;
}
}
if (ret == 0) {
VNC_DEBUG("Closing the connection: vnc_connection_read() - ret=0");
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Server closed the connection");
return -EPIPE;
}
//VNC_DEBUG("Read wire %p %d -> %d", data, len, ret);
@@ -796,9 +830,9 @@ static int vnc_connection_read_sasl(VncConnection *conn)
&priv->saslDecoded, &priv->saslDecodedLength);
g_free(encoded);
if (err != SASL_OK) {
- VNC_DEBUG("Failed to decode SASL data %s",
- sasl_errstring(err, NULL, NULL));
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn,
+ "Failed to decode SASL data %s",
+ sasl_errstring(err, NULL, NULL));
return -EINVAL;
}
priv->saslDecodedOffset = 0;
@@ -816,7 +850,7 @@ static int vnc_connection_read_sasl(VncConnection *conn)
priv->saslDecodedLength = priv->saslDecodedOffset = 0;
priv->saslDecoded = NULL;
}
- //VNC_DEBUG("Done read write %d - %d", want, priv->has_error);
+
return want;
}
#endif
@@ -842,7 +876,6 @@ static int vnc_connection_read_buf(VncConnection *conn)
#ifdef HAVE_SASL
VncConnectionPrivate *priv = conn->priv;
- //VNC_DEBUG("Start read %d", priv->has_error);
if (priv->saslconn)
return vnc_connection_read_sasl(conn);
else
@@ -861,7 +894,7 @@ static int vnc_connection_read(VncConnection *conn, void *data, size_t len)
char *ptr = data;
size_t offset = 0;
- if (priv->has_error) return -EINVAL;
+ if (priv->coroutine_stop) return -EINVAL;
while (offset < len) {
size_t tmp;
@@ -871,8 +904,7 @@ static int vnc_connection_read(VncConnection *conn, void *data, size_t len)
if (vnc_connection_use_compression(conn)) {
int ret = vnc_connection_zread(conn, ptr + offset, len);
if (ret == -1) {
- VNC_DEBUG("Closing the connection: vnc_connection_read() - zread() failed");
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failure decompressing data");
return -errno;
}
offset += ret;
@@ -913,7 +945,7 @@ static void vnc_connection_flush_wire(VncConnection *conn,
int ret;
gboolean blocking = FALSE;
- if (priv->has_error) return;
+ if (priv->coroutine_stop) return;
if (priv->tls_session) {
ret = gnutls_write(priv->tls_session,
@@ -943,14 +975,12 @@ static void vnc_connection_flush_wire(VncConnection *conn,
if (blocking) {
g_io_wait(priv->sock, G_IO_OUT);
} else {
- VNC_DEBUG("Closing the connection: vnc_connection_flush %d", errno);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failed to flush data");
return;
}
}
if (ret == 0) {
- VNC_DEBUG("Closing the connection: vnc_connection_flush");
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failed to any flush data");
return;
}
offset += ret;
@@ -975,9 +1005,8 @@ static void vnc_connection_flush_sasl(VncConnection *conn)
priv->write_offset,
&output, &outputlen);
if (err != SASL_OK) {
- VNC_DEBUG("Failed to encode SASL data %s",
- sasl_errstring(err, NULL, NULL));
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Failed to encode SASL data %s",
+ sasl_errstring(err, NULL, NULL));
return;
}
//VNC_DEBUG("Flush SASL %d: %p %d", priv->write_offset, output, outputlen);
@@ -1006,7 +1035,6 @@ static void vnc_connection_flush(VncConnection *conn)
{
VncConnectionPrivate *priv = conn->priv;
- //VNC_DEBUG("Start flush write %d", priv->has_error);
#ifdef HAVE_SASL
if (priv->saslconn)
vnc_connection_flush_sasl(conn);
@@ -1356,70 +1384,78 @@ static int vnc_connection_validate_certificate(VncConnection *conn)
VNC_DEBUG("Validating");
if ((ret = gnutls_certificate_verify_peers2 (priv->tls_session, &status)) < 0) {
- VNC_DEBUG("Verify failed %s", gnutls_strerror(ret));
+ vnc_connection_set_error(conn, "Failed to verify peer %s", gnutls_strerror(ret));
return FALSE;
}
if ((now = time(NULL)) == ((time_t)-1)) {
+ vnc_connection_set_error(conn, "%s", "Failed to get current time");
return FALSE;
}
if (status != 0) {
- if (status & GNUTLS_CERT_INVALID)
- VNC_DEBUG ("The certificate is not trusted.");
-
- if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
- VNC_DEBUG ("The certificate hasn't got a known issuer.");
-
- if (status & GNUTLS_CERT_REVOKED)
- VNC_DEBUG ("The certificate has been revoked.");
-
- if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
- VNC_DEBUG ("The certificate uses an insecure algorithm");
-
+ if (status & GNUTLS_CERT_INVALID) {
+ vnc_connection_set_error(conn, "%s", "The certificate is not trusted.");
+ } else if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
+ vnc_connection_set_error(conn, "%s", "The certificate hasn't got a known issuer.");
+ } else if (status & GNUTLS_CERT_REVOKED) {
+ vnc_connection_set_error(conn, "%s", "The certificate has been revoked.");
+ } else if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
+ vnc_connection_set_error(conn, "%s", "The certificate uses an insecure algorithm");
+ } else {
+ vnc_connection_set_error(conn, "%s", "The certificate is not valid");
+ }
return FALSE;
} else {
VNC_DEBUG("Certificate is valid.");
}
- if (gnutls_certificate_type_get(priv->tls_session) != GNUTLS_CRT_X509)
+ if (gnutls_certificate_type_get(priv->tls_session) != GNUTLS_CRT_X509) {
+ vnc_connection_set_error(conn, "%s", "Only x509 certificates are supported");
return FALSE;
+ }
- if (!(certs = gnutls_certificate_get_peers(priv->tls_session, &nCerts)))
+ if (!(certs = gnutls_certificate_get_peers(priv->tls_session, &nCerts))) {
+ vnc_connection_set_error(conn, "%s", "Unable to query certificate peers");
return FALSE;
+ }
for (i = 0 ; i < nCerts ; i++) {
gnutls_x509_crt_t cert;
VNC_DEBUG ("Checking chain %d", i);
- if (gnutls_x509_crt_init (&cert) < 0)
+ if (gnutls_x509_crt_init (&cert) < 0) {
+ vnc_connection_set_error(conn, "%s", "Unable to initialize cert");
return FALSE;
+ }
if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
gnutls_x509_crt_deinit (cert);
+ vnc_connection_set_error(conn, "%s", "Unable to import certificate");
return FALSE;
}
if (gnutls_x509_crt_get_expiration_time (cert) < now) {
- VNC_DEBUG("The certificate has expired");
+ vnc_connection_set_error(conn, "%s", "The certificate has expired");
gnutls_x509_crt_deinit (cert);
return FALSE;
}
if (gnutls_x509_crt_get_activation_time (cert) > now) {
- VNC_DEBUG("The certificate is not yet activated");
+ vnc_connection_set_error(conn, "%s", "The certificate is not yet activated");
gnutls_x509_crt_deinit (cert);
return FALSE;
}
if (i == 0) {
if (!priv->host) {
- VNC_DEBUG ("No hostname provided for certificate verification");
+ vnc_connection_set_error(conn, "%s", "No hostname provided for certificate verification");
gnutls_x509_crt_deinit (cert);
return FALSE;
}
if (!gnutls_x509_crt_check_hostname (cert, priv->host)) {
- VNC_DEBUG ("The certificate's owner does not match hostname '%s'",
- priv->host);
+ vnc_connection_set_error(conn,
+ "The certificate's owner does not match hostname '%s'",
+ priv->host);
gnutls_x509_crt_deinit (cert);
return FALSE;
}
@@ -1485,7 +1521,7 @@ gboolean vnc_connection_has_error(VncConnection *conn)
{
VncConnectionPrivate *priv = conn->priv;
- return priv->has_error;
+ return priv->coroutine_stop;
}
/**
@@ -2685,7 +2721,7 @@ static void vnc_connection_tight_update_jpeg(VncConnection *conn, guint16 x, gui
GdkPixbuf *p;
if (!gdk_pixbuf_loader_write(loader, data, length, NULL)) {
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Unable to decode jpeg data");
return;
}
@@ -2776,8 +2812,8 @@ static void vnc_connection_tight_update(VncConnection *conn,
vnc_connection_tight_update_gradient(conn, x, y, width, height);
break;
default: /* error */
- VNC_DEBUG("Closing the connection: vnc_connection_tight_update() - filter_id unknown");
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Unexpected tight filter id %d",
+ filter_id);
break;
}
@@ -2808,9 +2844,8 @@ static void vnc_connection_tight_update(VncConnection *conn,
jpeg_data, length);
g_free(jpeg_data);
} else {
- /* error */
- VNC_DEBUG("Closing the connection: vnc_connection_tight_update() - ccontrol unknown");
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Unexpected tight ccontrol %d",
+ ccontrol);
}
}
@@ -2819,7 +2854,7 @@ static void vnc_connection_update(VncConnection *conn, int x, int y, int width,
VncConnectionPrivate *priv = conn->priv;
struct signal_data sigdata;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return;
VNC_DEBUG("Notify update area (%dx%d) at location %d,%d", width, height, x, y);
@@ -2837,7 +2872,7 @@ static void vnc_connection_bell(VncConnection *conn)
VncConnectionPrivate *priv = conn->priv;
struct signal_data sigdata;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return;
VNC_DEBUG("Server beep");
@@ -2853,7 +2888,7 @@ static void vnc_connection_server_cut_text(VncConnection *conn,
struct signal_data sigdata;
GString *text;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return;
text = g_string_new_len ((const gchar *)data, len);
@@ -2869,7 +2904,7 @@ static void vnc_connection_resize(VncConnection *conn, int width, int height)
VncConnectionPrivate *priv = conn->priv;
struct signal_data sigdata;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return;
priv->width = width;
@@ -2885,7 +2920,7 @@ static void vnc_connection_pixel_format(VncConnection *conn)
VncConnectionPrivate *priv = conn->priv;
struct signal_data sigdata;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return;
sigdata.params.pixelFormat = &priv->fmt;
@@ -2903,7 +2938,7 @@ static void vnc_connection_pointer_type_change(VncConnection *conn, gboolean abs
return;
priv->absPointer = absPointer;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return;
sigdata.params.absPointer = absPointer;
@@ -2954,7 +2989,7 @@ static void vnc_connection_rich_cursor(VncConnection *conn, int x, int y, int wi
priv->cursor = vnc_cursor_new(pixbuf, x, y, width, height);
}
- if (priv->has_error)
+ if (priv->coroutine_stop)
return;
sigdata.params.cursor = priv->cursor;
@@ -3009,7 +3044,7 @@ static void vnc_connection_xcursor(VncConnection *conn, int x, int y, int width,
priv->cursor = vnc_cursor_new(pixbuf, x, y, width, height);
}
- if (priv->has_error)
+ if (priv->coroutine_stop)
return;
sigdata.params.cursor = priv->cursor;
@@ -3033,9 +3068,9 @@ static gboolean vnc_connection_validate_boundary(VncConnection *conn,
VncConnectionPrivate *priv = conn->priv;
if ((x + width) > priv->width || (y + height) > priv->height) {
- VNC_DEBUG("Framebuffer update %dx%d at %d,%d outside boundary %dx%d",
- width, height, x, y, priv->width, priv->height);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Framebuffer update %dx%d at %d,%d "
+ "outside boundary %dx%d",
+ width, height, x, y, priv->width, priv->height);
}
return !vnc_connection_has_error(conn);
@@ -3130,8 +3165,7 @@ static gboolean vnc_connection_framebuffer_update(VncConnection *conn, gint32 et
vnc_connection_audio_enable(conn);
break;
default:
- VNC_DEBUG("Received an unknown encoding type: %d", etype);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Received an unknown encoding type: %d", etype);
break;
}
@@ -3306,18 +3340,12 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
vnc_connection_read(conn, pad, 3);
n_text = vnc_connection_read_u32(conn);
if (n_text > (32 << 20)) {
- VNC_DEBUG("Closing the connection: vnc_connection_server_message() - cutText > allowed");
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Cut text length %u longer than permitted %u",
+ n_text, (32 << 20));
break;
}
data = g_new(char, n_text + 1);
- if (data == NULL) {
- VNC_DEBUG("Closing the connection: vnc_connection_server_message() - cutText - !data");
- priv->has_error = TRUE;
- break;
- }
-
vnc_connection_read(conn, data, n_text);
data[n_text] = 0;
@@ -3329,7 +3357,7 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
n_type = vnc_connection_read_u8(conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
break;
switch (n_type) {
@@ -3342,25 +3370,22 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
case VNC_CONNECTION_SERVER_MESSAGE_QEMU_AUDIO_DATA:
n_length = vnc_connection_read_u32(conn);
if (n_length > (1024*1024)) {
- VNC_DEBUG("Received audio message that is too large %u", n_length);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn,
+ "Audio sample length %d longer than permitted %u",
+ n_length, 1024 * 1024);
break;
}
- if (priv->has_error)
+ if (priv->coroutine_stop)
break;
if (!priv->audio) {
- VNC_DEBUG("No audio playback available");
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s",
+ "No audio playback sink configured");
break;
}
if (priv->audio_sample &&
((priv->audio_sample->capacity - priv->audio_sample->length) < n_length)) {
g_source_remove(priv->audio_timer);
- fprintf(stderr, "%u %u %u\n",
- priv->audio_sample->capacity,
- priv->audio_sample->length,
- n_length);
vnc_connection_audio_action(conn, VNC_AUDIO_PLAYBACK_DATA);
vnc_audio_sample_free(priv->audio_sample);
priv->audio_sample = NULL;
@@ -3381,7 +3406,7 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
if (priv->audio)
vnc_connection_audio_action(conn, VNC_AUDIO_PLAYBACK_START);
else
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "No audio sink configured");
break;
case VNC_CONNECTION_SERVER_MESSAGE_QEMU_AUDIO_STOP:
if (priv->audio) {
@@ -3393,23 +3418,20 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
}
vnc_connection_audio_action(conn, VNC_AUDIO_PLAYBACK_STOP);
} else {
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "No audio sink configured");
}
break;
default:
- VNC_DEBUG("Received unknown QEMU audio message: %u", (int)n_subtype);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Received unknown QEMU audio message: %u", (int)n_subtype);
break;
}
} break;
default:
- VNC_DEBUG("Received an unknown QEMU message: %u", n_type);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Received an unknown QEMU message: %u", n_type);
}
} break;
default:
- VNC_DEBUG("Received an unknown message: %u", msg);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Received an unknown message: %u", msg);
break;
}
@@ -3421,7 +3443,7 @@ static gboolean vnc_connection_has_credentials(gpointer data)
VncConnection *conn = data;
VncConnectionPrivate *priv = conn->priv;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return TRUE;
if (priv->want_cred_username && !priv->cred_username)
return FALSE;
@@ -3444,7 +3466,7 @@ static gboolean vnc_connection_gather_credentials(VncConnection *conn)
{
VncConnectionPrivate *priv = conn->priv;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
if (!vnc_connection_has_credentials(conn)) {
@@ -3479,7 +3501,7 @@ static gboolean vnc_connection_gather_credentials(VncConnection *conn)
g_value_array_free(authCred);
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
VNC_DEBUG("Waiting for missing credentials");
g_condition_wait(vnc_connection_has_credentials, conn);
@@ -3510,16 +3532,18 @@ static gboolean vnc_connection_check_auth_result(VncConnection *conn)
vnc_connection_read(conn, reason, len);
reason[len] = '\0';
VNC_DEBUG("Fail %s", reason);
- if (!priv->has_error) {
+ if (!priv->coroutine_stop) {
struct signal_data sigdata;
sigdata.params.authReason = reason;
+ vnc_connection_set_error(conn, "%s", reason);
vnc_connection_emit_main_context(conn, VNC_AUTH_FAILURE, &sigdata);
}
} else {
VNC_DEBUG("Fail auth no result");
- if (!priv->has_error) {
+ if (!priv->coroutine_stop) {
struct signal_data sigdata;
sigdata.params.authReason = "Unknown authentication failure";
+ vnc_connection_set_error(conn, "%s", "Unknown authentication failure");
vnc_connection_emit_main_context(conn, VNC_AUTH_FAILURE, &sigdata);
}
}
@@ -3935,32 +3959,37 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
err = sasl_client_init(NULL);
VNC_DEBUG("Client initialize SASL authentication %d", err);
if (err != SASL_OK) {
- VNC_DEBUG("failed to initialize SASL library: %d (%s)",
- err, sasl_errstring(err, NULL, NULL));
+ vnc_connection_set_error(conn,
+ "failed to initialize SASL library: %d (%s)",
+ err, sasl_errstring(err, NULL, NULL));
goto error;
}
/* Get local address in form IPADDR:PORT */
addr = g_socket_get_local_address(priv->sock, NULL);
if (!addr) {
- VNC_DEBUG("failed to get local address");
+ vnc_connection_set_error(conn, "%s", "failed to get local address");
goto error;
}
if ((g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV4 ||
g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV6) &&
- (localAddr = vnc_connection_addr_to_string(addr)) == NULL)
+ (localAddr = vnc_connection_addr_to_string(addr)) == NULL) {
+ vnc_connection_set_error(conn, "%s", "Unable to format address as string");
goto error;
+ }
/* Get remote address in form IPADDR:PORT */
addr = g_socket_get_remote_address(priv->sock, NULL);
if (!addr) {
- VNC_DEBUG("failed to get peer address");
+ vnc_connection_set_error(conn, "%s", "failed to get peer address");
goto error;
}
if ((g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV4 ||
g_socket_address_get_family(addr) == G_SOCKET_FAMILY_IPV6) &&
- (remoteAddr = vnc_connection_addr_to_string(addr)) == NULL)
+ (remoteAddr = vnc_connection_addr_to_string(addr)) == NULL) {
+ vnc_connection_set_error(conn, "%s", "Unable to format address as string");
goto error;
+ }
VNC_DEBUG("Client SASL new host:'%s' local:'%s' remote:'%s'", priv->host, localAddr, remoteAddr);
@@ -3976,8 +4005,9 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
g_free(remoteAddr);
if (err != SASL_OK) {
- VNC_DEBUG("Failed to create SASL client context: %d (%s)",
- err, sasl_errstring(err, NULL, NULL));
+ vnc_connection_set_error(conn,
+ "Failed to create SASL client context: %d (%s)",
+ err, sasl_errstring(err, NULL, NULL));
goto error;
}
@@ -3987,7 +4017,8 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
cipher = gnutls_cipher_get(priv->tls_session);
if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
- VNC_DEBUG("%s", "invalid cipher size for TLS session");
+ vnc_connection_set_error(conn, "%s",
+ "invalid cipher size for TLS session");
goto error;
}
ssf *= 8; /* key size is bytes, sasl wants bits */
@@ -3995,8 +4026,9 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
VNC_DEBUG("Setting external SSF %d", ssf);
err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf);
if (err != SASL_OK) {
- VNC_DEBUG("cannot set external SSF %d (%s)",
- err, sasl_errstring(err, NULL, NULL));
+ vnc_connection_set_error(conn,
+ "cannot set external SSF %d (%s)",
+ err, sasl_errstring(err, NULL, NULL));
goto error;
}
}
@@ -4012,41 +4044,32 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops);
if (err != SASL_OK) {
- VNC_DEBUG("cannot set security props %d (%s)",
- err, sasl_errstring(err, NULL, NULL));
+ vnc_connection_set_error(conn,
+ "cannot set security props %d (%s)",
+ err, sasl_errstring(err, NULL, NULL));
goto error;
}
/* Get the supported mechanisms from the server */
mechlistlen = vnc_connection_read_u32(conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
goto error;
if (mechlistlen > SASL_MAX_MECHLIST_LEN) {
- VNC_DEBUG("mechlistlen %d too long", mechlistlen);
+ vnc_connection_set_error(conn,
+ "mechlistlen %d too long",
+ mechlistlen);
goto error;
}
mechlist = g_malloc(mechlistlen+1);
vnc_connection_read(conn, mechlist, mechlistlen);
mechlist[mechlistlen] = '\0';
- if (priv->has_error) {
+ if (priv->coroutine_stop) {
g_free(mechlist);
mechlist = NULL;
goto error;
}
-#if 0
- if (wantmech) {
- if (strstr(mechlist, wantmech) == NULL) {
- VNC_DEBUG("SASL mechanism %s not supported by server",
- wantmech);
- VIR_FREE(iret.mechlist);
- goto error;
- }
- mechlist = wantmech;
- }
-#endif
-
restart:
/* Start the auth negotiation on the client end first */
VNC_DEBUG("Client start negotiation mechlist '%s'", mechlist);
@@ -4057,8 +4080,9 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
&clientoutlen,
&mechname);
if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
- VNC_DEBUG("Failed to start SASL negotiation: %d (%s)",
- err, sasl_errdetail(saslconn));
+ vnc_connection_set_error(conn,
+ "Failed to start SASL negotiation: %d (%s)",
+ err, sasl_errdetail(saslconn));
g_free(mechlist);
mechlist = NULL;
goto error;
@@ -4068,7 +4092,8 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
if (err == SASL_INTERACT) {
if (!vnc_connection_gather_sasl_credentials(conn,
interact)) {
- VNC_DEBUG("%s", "Failed to collect auth credentials");
+ vnc_connection_set_error(conn, "%s",
+ "Failed to collect auth credentials");
goto error;
}
goto restart;
@@ -4078,8 +4103,9 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
mechname, clientoutlen, clientout, clientout);
if (clientoutlen > SASL_MAX_DATA_LEN) {
- VNC_DEBUG("SASL negotiation data too long: %d bytes",
- clientoutlen);
+ vnc_connection_set_error(conn,
+ "SASL negotiation data too long: %d bytes",
+ clientoutlen);
goto error;
}
@@ -4095,18 +4121,19 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
vnc_connection_write_u32(conn, 0);
}
vnc_connection_flush(conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
goto error;
VNC_DEBUG("%s", "Getting sever start negotiation reply");
/* Read the 'START' message reply from server */
serverinlen = vnc_connection_read_u32(conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
goto error;
if (serverinlen > SASL_MAX_DATA_LEN) {
- VNC_DEBUG("SASL negotiation data too long: %d bytes",
- clientoutlen);
+ vnc_connection_set_error(conn,
+ "SASL negotiation data too long: %d bytes",
+ clientoutlen);
goto error;
}
@@ -4120,7 +4147,7 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
serverin = NULL;
}
complete = vnc_connection_read_u8(conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
goto error;
VNC_DEBUG("Client start result complete: %d. Data %d bytes %p '%s'",
@@ -4143,8 +4170,9 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
&clientout,
&clientoutlen);
if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) {
- VNC_DEBUG("Failed SASL step: %d (%s)",
- err, sasl_errdetail(saslconn));
+ vnc_connection_set_error(conn,
+ "Failed SASL step: %d (%s)",
+ err, sasl_errdetail(saslconn));
goto error;
}
@@ -4152,7 +4180,8 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
if (err == SASL_INTERACT) {
if (!vnc_connection_gather_sasl_credentials(conn,
interact)) {
- VNC_DEBUG("%s", "Failed to collect auth credentials");
+ vnc_connection_set_error(conn, "%s",
+ "Failed to collect auth credentials");
goto error;
}
goto restep;
@@ -4179,17 +4208,18 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
vnc_connection_write_u32(conn, 0);
}
vnc_connection_flush(conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
goto error;
VNC_DEBUG("Server step with %d bytes %p", clientoutlen, clientout);
serverinlen = vnc_connection_read_u32(conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
goto error;
if (serverinlen > SASL_MAX_DATA_LEN) {
- VNC_DEBUG("SASL negotiation data too long: %d bytes",
- clientoutlen);
+ vnc_connection_set_error(conn,
+ "SASL negotiation data too long: %d bytes",
+ clientoutlen);
goto error;
}
@@ -4203,7 +4233,7 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
serverin = NULL;
}
complete = vnc_connection_read_u8(conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
goto error;
VNC_DEBUG("Client step result complete: %d. Data %d bytes %p '%s'",
@@ -4222,14 +4252,16 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
if (!priv->tls_session) {
err = sasl_getprop(saslconn, SASL_SSF, &val);
if (err != SASL_OK) {
- VNC_DEBUG("cannot query SASL ssf on connection %d (%s)",
- err, sasl_errstring(err, NULL, NULL));
+ vnc_connection_set_error(conn,
+ "cannot query SASL ssf on connection %d (%s)",
+ err, sasl_errstring(err, NULL, NULL));
goto error;
}
ssf = *(const int *)val;
VNC_DEBUG("SASL SSF value %d", ssf);
if (ssf < 56) { /* 56 == DES level, good for Kerberos */
- VNC_DEBUG("negotiation SSF %d was not strong enough", ssf);
+ vnc_connection_set_error(conn,
+ "negotiated SSF %d was not strong enough", ssf);
goto error;
}
}
@@ -4243,7 +4275,6 @@ static gboolean vnc_connection_perform_auth_sasl(VncConnection *conn)
return ret;
error:
- priv->has_error = TRUE;
if (saslconn)
sasl_dispose(&saslconn);
return FALSE;
@@ -4259,19 +4290,18 @@ static gboolean vnc_connection_start_tls(VncConnection *conn, int anonTLS)
VNC_DEBUG("Do TLS handshake");
if (vnc_connection_tls_initialize() < 0) {
- VNC_DEBUG("Failed to init TLS");
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failed to init TLS");
return FALSE;
}
if (priv->tls_session == NULL) {
if (gnutls_init(&priv->tls_session, GNUTLS_CLIENT) < 0) {
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failed to allocate client session");
return FALSE;
}
if (gnutls_priority_set_direct(priv->tls_session, priority, NULL) < 0) {
gnutls_deinit(priv->tls_session);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failed to set priority");
return FALSE;
}
@@ -4279,12 +4309,12 @@ static gboolean vnc_connection_start_tls(VncConnection *conn, int anonTLS)
gnutls_anon_client_credentials anon_cred = vnc_connection_tls_initialize_anon_cred();
if (!anon_cred) {
gnutls_deinit(priv->tls_session);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failed to allocate credentials");
return FALSE;
}
if (gnutls_credentials_set(priv->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
gnutls_deinit(priv->tls_session);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failed to initialize credentials");
return FALSE;
}
} else {
@@ -4297,12 +4327,12 @@ static gboolean vnc_connection_start_tls(VncConnection *conn, int anonTLS)
gnutls_certificate_credentials_t x509_cred = vnc_connection_tls_initialize_cert_cred(conn);
if (!x509_cred) {
gnutls_deinit(priv->tls_session);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failed to allocate credentials");
return FALSE;
}
if (gnutls_credentials_set(priv->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
gnutls_deinit(priv->tls_session);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Failed to initialize credentials");
return FALSE;
}
}
@@ -4322,10 +4352,10 @@ static gboolean vnc_connection_start_tls(VncConnection *conn, int anonTLS)
g_io_wait(priv->sock, G_IO_OUT);
goto retry;
}
- VNC_DEBUG("Handshake failed %s", gnutls_strerror(ret));
gnutls_deinit(priv->tls_session);
priv->tls_session = NULL;
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Failed to complete handshake %s",
+ gnutls_strerror(ret));
return FALSE;
}
@@ -4335,8 +4365,6 @@ static gboolean vnc_connection_start_tls(VncConnection *conn, int anonTLS)
return TRUE;
} else {
if (!vnc_connection_validate_certificate(conn)) {
- VNC_DEBUG("Certificate validation failed");
- priv->has_error = TRUE;
return FALSE;
}
return TRUE;
@@ -4348,7 +4376,7 @@ static gboolean vnc_connection_has_auth_subtype(gpointer data)
VncConnection *conn = data;
VncConnectionPrivate *priv = conn->priv;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return TRUE;
if (priv->auth_subtype == VNC_CONNECTION_AUTH_INVALID)
return FALSE;
@@ -4411,8 +4439,7 @@ static gboolean vnc_connection_perform_auth_tls(VncConnection *conn)
}
if (nauth > sizeof(auth)) {
- VNC_DEBUG("Too many (%d) auth types", nauth);
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Too many (%d) auth types", nauth);
return FALSE;
}
for (i = 0 ; i < nauth ; i++) {
@@ -4423,15 +4450,15 @@ static gboolean vnc_connection_perform_auth_tls(VncConnection *conn)
VNC_DEBUG("Possible TLS sub-auth %d", auth[i]);
}
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
vnc_connection_choose_auth(conn, VNC_AUTH_CHOOSE_SUBTYPE, nauth, auth);
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
VNC_DEBUG("Waiting for TLS auth subtype");
g_condition_wait(vnc_connection_has_auth_subtype, conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
VNC_DEBUG("Choose auth %d", priv->auth_subtype);
@@ -4451,6 +4478,8 @@ static gboolean vnc_connection_perform_auth_tls(VncConnection *conn)
return vnc_connection_perform_auth_sasl(conn);
#endif
default:
+ vnc_connection_set_error(conn, "Auth subtype %d is not supported",
+ priv->auth_subtype);
return FALSE;
}
@@ -4469,7 +4498,7 @@ static gboolean vnc_connection_perform_auth_vencrypt(VncConnection *conn)
if (major != 0 &&
minor != 2) {
- VNC_DEBUG("Unsupported VeNCrypt version %d %d", major, minor);
+ vnc_connection_set_error(conn, "Unsupported VeNCrypt version %d %d", major, minor);
return FALSE;
}
@@ -4478,13 +4507,13 @@ static gboolean vnc_connection_perform_auth_vencrypt(VncConnection *conn)
vnc_connection_flush(conn);
status = vnc_connection_read_u8(conn);
if (status != 0) {
- VNC_DEBUG("Server refused VeNCrypt version %d %d", major, minor);
+ vnc_connection_set_error(conn, "Server refused VeNCrypt version %d %d", major, minor);
return FALSE;
}
nauth = vnc_connection_read_u8(conn);
if (nauth > (sizeof(auth)/sizeof(auth[0]))) {
- VNC_DEBUG("Too many (%d) auth types", nauth);
+ vnc_connection_set_error(conn, "Too many (%d) auth types", nauth);
return FALSE;
}
@@ -4496,15 +4525,15 @@ static gboolean vnc_connection_perform_auth_vencrypt(VncConnection *conn)
VNC_DEBUG("Possible VeNCrypt sub-auth %d", auth[i]);
}
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
vnc_connection_choose_auth(conn, VNC_AUTH_CHOOSE_SUBTYPE, nauth, auth);
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
VNC_DEBUG("Waiting for VeNCrypt auth subtype");
g_condition_wait(vnc_connection_has_auth_subtype, conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
VNC_DEBUG("Choose auth %d", priv->auth_subtype);
@@ -4514,7 +4543,8 @@ static gboolean vnc_connection_perform_auth_vencrypt(VncConnection *conn)
#ifndef DEBUG
if (priv->auth_subtype == VNC_CONNECTION_AUTH_VENCRYPT_PLAIN) {
- VNC_DEBUG("Cowardly refusing to transmit plain text password");
+ vnc_connection_set_error(conn, "%s",
+ "Cowardly refusing to transmit plain text password");
return FALSE;
}
#endif
@@ -4523,7 +4553,8 @@ static gboolean vnc_connection_perform_auth_vencrypt(VncConnection *conn)
vnc_connection_flush(conn);
status = vnc_connection_read_u8(conn);
if (status != 1) {
- VNC_DEBUG("Server refused VeNCrypt auth %d %d", priv->auth_subtype, status);
+ vnc_connection_set_error(conn,
+ "Server refused VeNCrypt auth %d %d", priv->auth_subtype, status);
return FALSE;
}
@@ -4539,7 +4570,6 @@ static gboolean vnc_connection_perform_auth_vencrypt(VncConnection *conn)
}
if (!vnc_connection_start_tls(conn, anonTLS)) {
- VNC_DEBUG("Could not start TLS");
return FALSE;
}
VNC_DEBUG("Completed TLS setup, do subauth %d", priv->auth_subtype);
@@ -4566,7 +4596,7 @@ static gboolean vnc_connection_perform_auth_vencrypt(VncConnection *conn)
#endif
default:
- VNC_DEBUG("Unknown auth subtype %d", priv->auth_subtype);
+ vnc_connection_set_error(conn, "Unknown auth subtype %d", priv->auth_subtype);
return FALSE;
}
}
@@ -4576,7 +4606,7 @@ static gboolean vnc_connection_has_auth_type(gpointer data)
VncConnection *conn = data;
VncConnectionPrivate *priv = conn->priv;
- if (priv->has_error)
+ if (priv->coroutine_stop)
return TRUE;
if (priv->auth_type == VNC_CONNECTION_AUTH_INVALID)
return FALSE;
@@ -4601,7 +4631,8 @@ static gboolean vnc_connection_perform_auth(VncConnection *conn)
return vnc_connection_check_auth_result(conn);
if (nauth > sizeof(auth)) {
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Too many auth types %u",
+ nauth);
return FALSE;
}
for (i = 0 ; i < nauth ; i++)
@@ -4612,15 +4643,15 @@ static gboolean vnc_connection_perform_auth(VncConnection *conn)
VNC_DEBUG("Possible auth %u", auth[i]);
}
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
vnc_connection_choose_auth(conn, VNC_AUTH_CHOOSE_TYPE, nauth, auth);
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
VNC_DEBUG("Waiting for auth type");
g_condition_wait(vnc_connection_has_auth_type, conn);
- if (priv->has_error)
+ if (priv->coroutine_stop)
return FALSE;
VNC_DEBUG("Choose auth %u", priv->auth_type);
@@ -4641,8 +4672,10 @@ static gboolean vnc_connection_perform_auth(VncConnection *conn)
return vnc_connection_perform_auth_vnc(conn);
case VNC_CONNECTION_AUTH_TLS:
- if (priv->minor < 7)
+ if (priv->minor < 7) {
+ vnc_connection_set_error(conn, "%s", "TLS auth requires protocol 3.8");
return FALSE;
+ }
return vnc_connection_perform_auth_tls(conn);
case VNC_CONNECTION_AUTH_VENCRYPT:
@@ -4664,8 +4697,8 @@ static gboolean vnc_connection_perform_auth(VncConnection *conn)
struct signal_data sigdata;
sigdata.params.authUnsupported = priv->auth_type;
vnc_connection_emit_main_context(conn, VNC_AUTH_UNSUPPORTED, &sigdata);
- priv->has_error = TRUE;
}
+ vnc_connection_set_error(conn, "Unsupported auth type %d", priv->auth_type);
return FALSE;
}
@@ -4893,6 +4926,16 @@ static void vnc_connection_class_init(VncConnectionClass *klass)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
+ signals[VNC_ERROR] =
+ g_signal_new ("vnc-error",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (VncConnectionClass, vnc_error),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
g_type_class_add_private(klass, sizeof(VncConnectionPrivate));
@@ -5028,7 +5071,9 @@ static void vnc_connection_close(VncConnection *conn)
memset(&priv->fmt, 0, sizeof(priv->fmt));
- priv->has_error = FALSE;
+ g_free(priv->error);
+ priv->error = NULL;
+ priv->coroutine_stop = FALSE;
}
@@ -5052,8 +5097,8 @@ void vnc_connection_shutdown(VncConnection *conn)
}
priv->fd = -1;
- priv->has_error = 1;
- VNC_DEBUG("Waking up couroutine to shutdown gracefully");
+ priv->coroutine_stop = TRUE;
+ VNC_DEBUG("Waking up coroutine to shutdown gracefully");
g_io_wakeup(&priv->wait);
/* Closing the socket triggers an I/O error in the
@@ -5144,14 +5189,16 @@ static gboolean vnc_connection_initialize(VncConnection *conn)
ret = sscanf(version, "RFB %03d.%03d\n", &priv->major, &priv->minor);
if (ret != 2) {
- VNC_DEBUG("Error while parsing server version");
+ vnc_connection_set_error(conn, "%s",
+ "Error while parsing server version");
goto fail;
}
VNC_DEBUG("Server version: %d.%d", priv->major, priv->minor);
if (vnc_connection_before_version(conn, 3, 3)) {
- VNC_DEBUG("Server version is not supported (%d.%d)", priv->major, priv->minor);
+ vnc_connection_set_error(conn,
+ "Server version is not supported (%d.%d)", priv->major, priv->minor);
goto fail;
} else if (vnc_connection_before_version(conn, 3, 7)) {
priv->minor = 3;
@@ -5183,8 +5230,11 @@ static gboolean vnc_connection_initialize(VncConnection *conn)
vnc_connection_read_pixel_format(conn, &priv->fmt);
n_name = vnc_connection_read_u32(conn);
- if (n_name > 4096)
+ if (n_name > 4096) {
+ vnc_connection_set_error(conn, "Name length %u too long",
+ n_name);
goto fail;
+ }
priv->name = g_new(char, n_name + 1);
@@ -5204,7 +5254,6 @@ static gboolean vnc_connection_initialize(VncConnection *conn)
return !vnc_connection_has_error(conn);
fail:
- priv->has_error = TRUE;
return !vnc_connection_has_error(conn);
}
@@ -5292,6 +5341,8 @@ static gboolean vnc_connection_open_addr_internal(VncConnection *conn)
VNC_DEBUG("Connecting with addr %p", priv->addr);
sock = vnc_connection_connect_socket(&priv->wait, priv->addr, &conn_error);
+ vnc_connection_set_error(conn, "Unable to connect: %s",
+ conn_error->message);
g_clear_error(&conn_error);
if (sock) {
priv->sock = sock;
@@ -5330,6 +5381,10 @@ static gboolean vnc_connection_open_host_internal(VncConnection *conn)
g_object_unref(sockaddr);
}
g_object_unref(enumerator);
+ if (!sock) {
+ vnc_connection_set_error(conn, "Unable to connect: %s",
+ conn_error->message);
+ }
g_clear_error(&conn_error);
if (sock) {
priv->sock = sock;
@@ -5568,7 +5623,7 @@ gboolean vnc_connection_set_auth_type(VncConnection *conn, unsigned int type)
VNC_DEBUG("Thinking about auth type %u", type);
if (priv->auth_type != VNC_CONNECTION_AUTH_INVALID) {
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Auth type has already been set");
return !vnc_connection_has_error(conn);
}
if (type != VNC_CONNECTION_AUTH_NONE &&
@@ -5578,9 +5633,9 @@ gboolean vnc_connection_set_auth_type(VncConnection *conn, unsigned int type)
type != VNC_CONNECTION_AUTH_TLS &&
type != VNC_CONNECTION_AUTH_VENCRYPT &&
type != VNC_CONNECTION_AUTH_SASL) {
- VNC_DEBUG("Unsupported auth type %u", type);
+ vnc_connection_set_error(conn, "Auth type %d is not supported",
+ type);
g_signal_emit(conn, VNC_AUTH_UNSUPPORTED, 0, type);
- priv->has_error = TRUE;
return !vnc_connection_has_error(conn);
}
VNC_DEBUG("Decided on auth type %u", type);
@@ -5608,11 +5663,12 @@ gboolean vnc_connection_set_auth_subtype(VncConnection *conn, unsigned int type)
VNC_DEBUG("Requested auth subtype %d", type);
if (priv->auth_type != VNC_CONNECTION_AUTH_VENCRYPT &&
priv->auth_type != VNC_CONNECTION_AUTH_TLS) {
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Auth type %d does not support subauth",
+ priv->auth_type);
return !vnc_connection_has_error(conn);
}
if (priv->auth_subtype != VNC_CONNECTION_AUTH_INVALID) {
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "%s", "Auth subtype has already been set");
return !vnc_connection_has_error(conn);
}
priv->auth_subtype = type;
@@ -5719,7 +5775,7 @@ gboolean vnc_connection_set_credential(VncConnection *conn, int type, const gcha
return vnc_connection_set_credential_x509(conn, data);
default:
- priv->has_error = TRUE;
+ vnc_connection_set_error(conn, "Unknown credential type %d", type);
}
return !vnc_connection_has_error(conn);
diff --git a/src/vncconnection.h b/src/vncconnection.h
index 72d3f38..8c1fa28 100644
--- a/src/vncconnection.h
+++ b/src/vncconnection.h
@@ -79,12 +79,13 @@ struct _VncConnectionClass
void (*vnc_initialized)(VncConnection *conn);
void (*vnc_disconnected)(VncConnection *conn);
void (*vnc_led_state)(VncConnection *conn);
+ void (*vnc_error)(VncConnection *conn, const char *message);
/*
* If adding fields to this struct, remove corresponding
* amount of padding to avoid changing overall struct size
*/
- gpointer _vnc_reserved[VNC_PADDING_LARGE - 4];
+ gpointer _vnc_reserved[VNC_PADDING_LARGE - 5];
};
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index bc3a4ef..00714bd 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -139,6 +139,7 @@ typedef enum
VNC_SERVER_CUT_TEXT,
VNC_BELL,
+ VNC_ERROR,
LAST_SIGNAL
} vnc_display_signals;
@@ -1648,6 +1649,17 @@ static void on_connected(VncConnection *conn G_GNUC_UNUSED,
}
+static void on_error(VncConnection *conn G_GNUC_UNUSED,
+ const char *message,
+ gpointer opaque)
+{
+ VncDisplay *obj = VNC_DISPLAY(opaque);
+
+ g_signal_emit(G_OBJECT(obj), signals[VNC_ERROR], 0, message);
+ VNC_DEBUG("VNC server error");
+}
+
+
static void on_initialized(VncConnection *conn G_GNUC_UNUSED,
gpointer opaque)
{
@@ -2303,6 +2315,17 @@ static void vnc_display_class_init(VncDisplayClass *klass)
G_TYPE_NONE,
0);
+ signals[VNC_ERROR] =
+ g_signal_new ("vnc-error",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
signals[VNC_AUTH_CREDENTIAL] =
g_signal_new ("vnc-auth-credential",
G_OBJECT_CLASS_TYPE (object_class),
@@ -2547,6 +2570,8 @@ static void vnc_display_init(VncDisplay *display)
G_CALLBACK(on_initialized), display);
g_signal_connect(G_OBJECT(priv->conn), "vnc-disconnected",
G_CALLBACK(on_disconnected), display);
+ g_signal_connect(G_OBJECT(priv->conn), "vnc-error",
+ G_CALLBACK(on_error), display);
priv->keycode_map = vnc_display_keymap_gdk2rfb_table(&priv->keycode_maplen);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]