diff --git a/0008-channel-delay-event-report-to-after-coroutine-exit.patch b/0008-channel-delay-event-report-to-after-coroutine-exit.patch new file mode 100644 index 0000000..00b61fa --- /dev/null +++ b/0008-channel-delay-event-report-to-after-coroutine-exit.patch @@ -0,0 +1,187 @@ +From 940c5f59f97861a33010c1fde5d8bce38d9f6c68 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 13 Jan 2015 14:51:31 +0100 +Subject: [PATCH spice-gtk 1/3] channel: delay event report to after coroutine + exit + +Move to a common place error reporting, after the coroutine exits. +--- + gtk/spice-channel-priv.h | 3 ++- + gtk/spice-channel.c | 41 ++++++++++++++++++++++------------------- + 2 files changed, 24 insertions(+), 20 deletions(-) + +diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h +index bd7f490..d70cf86 100644 +--- a/gtk/spice-channel-priv.h ++++ b/gtk/spice-channel-priv.h +@@ -66,7 +66,6 @@ struct _SpiceMsgIn { + + enum spice_channel_state { + SPICE_CHANNEL_STATE_UNCONNECTED = 0, +- SPICE_CHANNEL_STATE_FAILED_AUTHENTICATION, + SPICE_CHANNEL_STATE_RECONNECTING, + SPICE_CHANNEL_STATE_CONNECTING, + SPICE_CHANNEL_STATE_READY, +@@ -110,6 +109,8 @@ struct _SpiceChannelPrivate { + + char name[16]; + enum spice_channel_state state; ++ SpiceChannelEvent event; ++ + spice_parse_channel_func_t parser; + SpiceMessageMarshallers *marshallers; + guint channel_watch; +diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c +index fb7b0d5..204b250 100644 +--- a/gtk/spice-channel.c ++++ b/gtk/spice-channel.c +@@ -1067,7 +1067,7 @@ static void spice_channel_failed_authentication(SpiceChannel *channel) + SPICE_CLIENT_ERROR_AUTH_NEEDS_PASSWORD, + _("Authentication failed: password is required")); + +- c->state = SPICE_CHANNEL_STATE_FAILED_AUTHENTICATION; ++ c->event = SPICE_CHANNEL_ERROR_AUTH; + + c->has_error = TRUE; /* force disconnect */ + } +@@ -1083,7 +1083,7 @@ static gboolean spice_channel_recv_auth(SpiceChannel *channel) + if (rc != sizeof(link_res)) { + CHANNEL_DEBUG(channel, "incomplete auth reply (%d/%" G_GSIZE_FORMAT ")", + rc, sizeof(link_res)); +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_LINK); ++ c->event = SPICE_CHANNEL_ERROR_LINK; + return FALSE; + } + +@@ -1223,7 +1223,7 @@ error: + return FALSE; + } + +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_LINK); ++ c->event = SPICE_CHANNEL_ERROR_LINK; + return FALSE; + } + +@@ -1694,8 +1694,7 @@ static gboolean spice_channel_recv_link_msg(SpiceChannel *channel) + if (c->peer_pos != c->peer_hdr.size) { + g_critical("%s: %s: incomplete link reply (%d/%d)", + c->name, __FUNCTION__, rc, c->peer_hdr.size); +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_LINK); +- return FALSE; ++ goto error; + } + switch (c->peer_msg->error) { + case SPICE_LINK_ERR_OK: +@@ -1764,7 +1763,7 @@ static gboolean spice_channel_recv_link_msg(SpiceChannel *channel) + + error: + SPICE_CHANNEL_GET_CLASS(channel)->channel_disconnect(channel); +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_LINK); ++ c->event = SPICE_CHANNEL_ERROR_LINK; + return FALSE; + } + +@@ -2154,12 +2153,15 @@ static gboolean spice_channel_iterate(SpiceChannel *channel) + /* We don't want to report an error if the socket was closed gracefully + * on the other end (VM shutdown) */ + ret = g_socket_condition_check(c->sock, G_IO_IN | G_IO_ERR | G_IO_HUP); ++ + if (ret & (G_IO_ERR|G_IO_HUP)) { + CHANNEL_DEBUG(channel, "channel got error"); ++ + if (c->state > SPICE_CHANNEL_STATE_CONNECTING) { +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, +- c->state == SPICE_CHANNEL_STATE_READY ? +- SPICE_CHANNEL_ERROR_IO : SPICE_CHANNEL_ERROR_LINK); ++ if (c->state == SPICE_CHANNEL_STATE_READY) ++ c->event = SPICE_CHANNEL_ERROR_IO; ++ else ++ c->event = SPICE_CHANNEL_ERROR_LINK; + } + } + return FALSE; +@@ -2180,8 +2182,9 @@ static gboolean spice_channel_delayed_unref(gpointer data) + + g_return_val_if_fail(c->coroutine.coroutine.exited == TRUE, FALSE); + +- if (c->state == SPICE_CHANNEL_STATE_FAILED_AUTHENTICATION) { +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_AUTH); ++ if (c->event != SPICE_CHANNEL_NONE) { ++ g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, c->event); ++ c->event = SPICE_CHANNEL_NONE; + g_clear_error(&c->error); + } + +@@ -2292,13 +2295,13 @@ static void *spice_channel_coroutine(void *data) + if (spice_session_get_client_provided_socket(c->session)) { + if (c->fd < 0) { + g_critical("fd not provided!"); +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_CONNECT); ++ c->event = SPICE_CHANNEL_ERROR_CONNECT; + goto cleanup; + } + + if (!(c->sock = g_socket_new_from_fd(c->fd, NULL))) { + CHANNEL_DEBUG(channel, "Failed to open socket from fd %d", c->fd); +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_CONNECT); ++ c->event = SPICE_CHANNEL_ERROR_CONNECT; + goto cleanup; + } + +@@ -2318,8 +2321,7 @@ reconnect: + goto reconnect; + } else { + CHANNEL_DEBUG(channel, "Connect error"); +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_CONNECT); +- g_clear_error(&c->error); ++ c->event = SPICE_CHANNEL_ERROR_CONNECT; + goto cleanup; + } + } +@@ -2331,7 +2333,7 @@ reconnect: + c->ctx = SSL_CTX_new(SSLv23_method()); + if (c->ctx == NULL) { + g_critical("SSL_CTX_new failed"); +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_TLS); ++ c->event = SPICE_CHANNEL_ERROR_TLS; + goto cleanup; + } + +@@ -2347,7 +2349,7 @@ reconnect: + g_warning("only pubkey active"); + verify = SPICE_SESSION_VERIFY_PUBKEY; + } else { +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_TLS); ++ c->event = SPICE_CHANNEL_ERROR_TLS; + goto cleanup; + } + } +@@ -2365,7 +2367,7 @@ reconnect: + c->ssl = SSL_new(c->ctx); + if (c->ssl == NULL) { + g_critical("SSL_new failed"); +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_TLS); ++ c->event = SPICE_CHANNEL_ERROR_TLS; + goto cleanup; + } + +@@ -2394,7 +2396,7 @@ ssl_reconnect: + } else { + g_warning("%s: SSL_connect: %s", + c->name, ERR_error_string(rc, NULL)); +- g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_TLS); ++ c->event = SPICE_CHANNEL_ERROR_TLS; + goto cleanup; + } + } +@@ -2430,6 +2432,7 @@ cleanup: + SPICE_CHANNEL_GET_CLASS(channel)->channel_disconnect(channel); + + if (c->state == SPICE_CHANNEL_STATE_RECONNECTING) { ++ g_warn_if_fail(c->event == SPICE_CHANNEL_NONE); + spice_channel_connect(channel); + g_object_unref(channel); + } else +-- +2.1.0 + diff --git a/0009-channel-reset-tls-state-when-client-calls-connect.patch b/0009-channel-reset-tls-state-when-client-calls-connect.patch new file mode 100644 index 0000000..921e6cf --- /dev/null +++ b/0009-channel-reset-tls-state-when-client-calls-connect.patch @@ -0,0 +1,82 @@ +From 26b7767d4831be91ccc3c922276b04118f8b3277 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 13 Jan 2015 17:26:18 +0100 +Subject: [PATCH spice-gtk 2/3] channel: reset tls state when client calls + connect + +The channel TLS state is kept during disconnection and reset, for +automatic reconnection and migrations reasons. However, when +spice_channel_connect() is called by client, it should first try +non-TLS connection. +--- + gtk/spice-channel.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c +index 204b250..99065d3 100644 +--- a/gtk/spice-channel.c ++++ b/gtk/spice-channel.c +@@ -55,6 +55,7 @@ static void channel_disconnect(SpiceChannel *channel); + static void channel_reset(SpiceChannel *channel, gboolean migrating); + static void spice_channel_reset_capabilities(SpiceChannel *channel); + static void spice_channel_send_migration_handshake(SpiceChannel *channel); ++static gboolean channel_connect(SpiceChannel *channel, gboolean tls); + + /** + * SECTION:spice-channel +@@ -2433,7 +2434,7 @@ cleanup: + + if (c->state == SPICE_CHANNEL_STATE_RECONNECTING) { + g_warn_if_fail(c->event == SPICE_CHANNEL_NONE); +- spice_channel_connect(channel); ++ channel_connect(channel, c->tls); + g_object_unref(channel); + } else + g_idle_add(spice_channel_delayed_unref, data); +@@ -2465,7 +2466,7 @@ static gboolean connect_delayed(gpointer data) + } + + /* any context */ +-static gboolean channel_connect(SpiceChannel *channel) ++static gboolean channel_connect(SpiceChannel *channel, gboolean tls) + { + SpiceChannelPrivate *c = channel->priv; + +@@ -2478,6 +2479,7 @@ static gboolean channel_connect(SpiceChannel *channel) + } + + c->state = SPICE_CHANNEL_STATE_CONNECTING; ++ c->tls = tls; + + if (spice_session_get_client_provided_socket(c->session)) { + if (c->fd == -1) { +@@ -2519,7 +2521,7 @@ gboolean spice_channel_connect(SpiceChannel *channel) + + g_return_val_if_fail(channel->priv->fd == -1, FALSE); + +- return channel_connect(channel); ++ return channel_connect(channel, FALSE); + } + + /** +@@ -2552,7 +2554,7 @@ gboolean spice_channel_open_fd(SpiceChannel *channel, int fd) + + c->fd = fd; + +- return channel_connect(channel); ++ return channel_connect(channel, FALSE); + } + + /* system or coroutine context */ +@@ -2651,7 +2653,7 @@ static void channel_disconnect(SpiceChannel *channel) + g_return_if_fail(SPICE_IS_CHANNEL(channel)); + + if (c->state == SPICE_CHANNEL_STATE_SWITCHING) { +- spice_channel_connect(channel); ++ channel_connect(channel, c->tls); + spice_session_set_migration_state(spice_channel_get_session(channel), + SPICE_SESSION_MIGRATION_NONE); + } +-- +2.1.0 + diff --git a/0010-channel-reset-connection-state-on-error.patch b/0010-channel-reset-connection-state-on-error.patch new file mode 100644 index 0000000..b5b4f3b --- /dev/null +++ b/0010-channel-reset-connection-state-on-error.patch @@ -0,0 +1,28 @@ +From 61f70b689044ea53f4103e79a128af640c003f48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 13 Jan 2015 16:33:52 +0100 +Subject: [PATCH spice-gtk 3/3] channel: reset connection state on error + +Fix regression introduced in 6b475802, to permit reconnection on error, +the channel state must be < STATE_CONNECTING. Since the error is +reported after coroutine exits and channel is reset, the state can be +modified before throwing the error now. +--- + gtk/spice-channel.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c +index 99065d3..eec63b1 100644 +--- a/gtk/spice-channel.c ++++ b/gtk/spice-channel.c +@@ -2184,6 +2184,7 @@ static gboolean spice_channel_delayed_unref(gpointer data) + g_return_val_if_fail(c->coroutine.coroutine.exited == TRUE, FALSE); + + if (c->event != SPICE_CHANNEL_NONE) { ++ c->state = SPICE_CHANNEL_STATE_UNCONNECTED; + g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, c->event); + c->event = SPICE_CHANNEL_NONE; + g_clear_error(&c->error); +-- +2.1.0 +