summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk/channel-main.c16
-rw-r--r--gtk/spice-channel.c4
-rw-r--r--gtk/spice-session-priv.h1
-rw-r--r--gtk/spice-session.c104
4 files changed, 102 insertions, 23 deletions
diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index b5bdafd..b099878 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -230,6 +230,9 @@ static void spice_main_channel_dispose(GObject *obj)
g_source_remove(c->switch_host_delayed_id);
c->switch_host_delayed_id = 0;
}
+
+ if (G_OBJECT_CLASS(spice_main_channel_parent_class)->dispose)
+ G_OBJECT_CLASS(spice_main_channel_parent_class)->dispose(obj);
}
static void spice_main_channel_finalize(GObject *obj)
@@ -907,6 +910,7 @@ static void main_handle_channels_list(SpiceChannel *channel, spice_msg_in *in)
c->id = msg->channels[i].id;
/* no need to explicitely switch to main context, since
synchronous call is not needed. */
+ /* no need to track idle, session is refed */
g_idle_add((GSourceFunc)_channel_new, c);
}
}
@@ -1212,13 +1216,17 @@ static void main_handle_migrate_begin(SpiceChannel *channel, spice_msg_in *in)
mig.channel = channel;
mig.info = msg;
mig.from = coroutine_self();
- g_idle_add(migrate_connect, &mig); /* TODO: track idle */
+
+ /* no need to track idle, call is sync for this coroutine */
+ g_idle_add(migrate_connect, &mig);
/* switch to main loop and wait for connections */
coroutine_yield(NULL);
+ g_return_if_fail(mig.session != NULL);
if (mig.nchannels != 0) {
reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR;
+ spice_session_disconnect(mig.session);
} else {
SPICE_DEBUG("migration: connections all ok");
reply_type = SPICE_MSGC_MAIN_MIGRATE_CONNECTED;
@@ -1285,7 +1293,11 @@ static void main_handle_migrate_switch_host(SpiceChannel *channel, spice_msg_in
static void main_handle_migrate_cancel(SpiceChannel *channel,
spice_msg_in *in G_GNUC_UNUSED)
{
- g_warning("%s: TODO", __FUNCTION__);
+ SpiceSession *session;
+
+ SPICE_DEBUG("migrate_cancel");
+ session = spice_channel_get_session(channel);
+ spice_session_abort_migration(session);
}
static spice_msg_handler main_handlers[] = {
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index 3fd900a..6847f59 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -133,6 +133,8 @@ static void spice_channel_dispose(GObject *gobject)
SpiceChannel *channel = SPICE_CHANNEL(gobject);
spice_channel *c = channel->priv;
+ SPICE_DEBUG("%s: %s %p", c->name, __FUNCTION__, gobject);
+
if (c->session)
spice_session_channel_destroy(c->session, channel);
@@ -1421,7 +1423,7 @@ static gboolean spice_channel_delayed_unref(gpointer data)
spice_channel *c = channel->priv;
g_return_val_if_fail(channel != NULL, FALSE);
- SPICE_DEBUG("Delayed unref channel=%p", channel);
+ SPICE_DEBUG("Delayed unref channel %s %p", c->name, channel);
g_return_val_if_fail(c->coroutine.exited == TRUE, FALSE);
diff --git a/gtk/spice-session-priv.h b/gtk/spice-session-priv.h
index 6e99849..f6a6b7f 100644
--- a/gtk/spice-session-priv.h
+++ b/gtk/spice-session-priv.h
@@ -39,6 +39,7 @@ guint32 spice_session_get_mm_time(SpiceSession *session);
void spice_session_migrate_disconnect(SpiceSession *session);
void spice_session_set_migration(SpiceSession *session, SpiceSession *migration);
+void spice_session_abort_migration(SpiceSession *session);
void spice_session_set_port(SpiceSession *session, int port, gboolean tls);
diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index c5b48ce..23fd345 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -47,7 +47,7 @@ struct spice_session {
gboolean client_provided_sockets;
guint64 mm_time_at_clock;
SpiceSession *migration;
- guint migration_left;
+ GList *migration_left;
gboolean disconnecting;
};
@@ -128,11 +128,23 @@ static void
spice_session_dispose(GObject *gobject)
{
SpiceSession *session = SPICE_SESSION(gobject);
+ spice_session *s = session->priv;
SPICE_DEBUG("session dispose");
spice_session_disconnect(session);
+ if (s->migration) {
+ spice_session_disconnect(s->migration);
+ g_object_unref(s->migration);
+ s->migration = NULL;
+ }
+
+ if (s->migration_left) {
+ g_list_free(s->migration_left);
+ s->migration_left = NULL;
+ }
+
/* Chain up to the parent class */
if (G_OBJECT_CLASS(spice_session_parent_class)->dispose)
G_OBJECT_CLASS(spice_session_parent_class)->dispose(gobject);
@@ -586,8 +598,8 @@ void spice_session_migrate_disconnect(SpiceSession *session)
spice_channel_destroy(item->channel); /* /!\ item and channel are destroy() after this call */
}
- g_return_if_fail(!ring_is_empty(&s->channels) &&
- ring_get_head(&s->channels) == ring_get_tail(&s->channels));
+ g_warn_if_fail(!ring_is_empty(&s->channels) &&
+ ring_get_head(&s->channels) == ring_get_tail(&s->channels));
}
G_GNUC_INTERNAL
@@ -614,30 +626,26 @@ void spice_session_set_migration(SpiceSession *session, SpiceSession *migration)
s->tls_port = m->tls_port;
m->tls_port = tmp;
+ g_warn_if_fail(ring_get_length(&s->channels) == ring_get_length(&m->channels));
+
SPICE_DEBUG("migration channels left:%d (in migration:%d)",
ring_get_length(&s->channels), ring_get_length(&m->channels));
- s->migration_left = ring_get_length(&s->channels);
+ s->migration_left = spice_session_get_channels(session);
}
G_GNUC_INTERNAL
-void spice_session_channel_migrate(SpiceSession *session, SpiceChannel *channel)
+SpiceChannel* get_channel_by_id_and_type(SpiceSession *session,
+ gint id, gint type)
{
- spice_session *s = SPICE_SESSION_GET_PRIVATE(session);
RingItem *ring, *next;
+ spice_session *s = session->priv;
struct channel *c;
- gint id, type;
-
- g_return_if_fail(s != NULL);
- g_return_if_fail(s->migration != NULL);
- g_return_if_fail(SPICE_IS_CHANNEL(channel));
- id = spice_channel_get_channel_id(channel);
- type = spice_channel_get_channel_type(channel);
- SPICE_DEBUG("migrating channel id:%d type:%d", id, type);
+ g_return_val_if_fail(s != NULL, NULL);
- for (ring = ring_get_head(&s->migration->priv->channels);
+ for (ring = ring_get_head(&s->channels);
ring != NULL; ring = next) {
- next = ring_next(&s->migration->priv->channels, ring);
+ next = ring_next(&s->channels, ring);
c = SPICE_CONTAINEROF(ring, struct channel, link);
if (c == NULL || c->channel == NULL) {
g_warn_if_reached();
@@ -648,11 +656,64 @@ void spice_session_channel_migrate(SpiceSession *session, SpiceChannel *channel)
type == spice_channel_get_channel_type(c->channel))
break;
}
- g_return_if_fail(ring != NULL);
+ g_return_val_if_fail(ring != NULL, NULL);
+
+ return c->channel;
+}
+
+G_GNUC_INTERNAL
+void spice_session_abort_migration(SpiceSession *session)
+{
+ spice_session *s = SPICE_SESSION_GET_PRIVATE(session);
+ RingItem *ring, *next;
+ struct channel *c;
+
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(s->migration != NULL);
+
+ for (ring = ring_get_head(&s->channels);
+ ring != NULL; ring = next) {
+ next = ring_next(&s->channels, ring);
+ c = SPICE_CONTAINEROF(ring, struct channel, link);
+
+ if (g_list_find(s->migration_left, c->channel))
+ continue;
+
+ spice_channel_swap(c->channel,
+ get_channel_by_id_and_type(s->migration,
+ spice_channel_get_channel_id(c->channel),
+ spice_channel_get_channel_type(c->channel)));
+ }
+
+ g_list_free(s->migration_left);
+ s->migration_left = NULL;
+ spice_session_disconnect(s->migration);
+ g_object_unref(s->migration);
+ s->migration = NULL;
+}
+
+G_GNUC_INTERNAL
+void spice_session_channel_migrate(SpiceSession *session, SpiceChannel *channel)
+{
+ spice_session *s = SPICE_SESSION_GET_PRIVATE(session);
+ SpiceChannel *c;
+ gint id, type;
+
+ g_return_if_fail(s != NULL);
+ g_return_if_fail(s->migration != NULL);
+ g_return_if_fail(SPICE_IS_CHANNEL(channel));
- spice_channel_swap(channel, c->channel);
- s->migration_left--;
- if (s->migration_left == 0) {
+ id = spice_channel_get_channel_id(channel);
+ type = spice_channel_get_channel_type(channel);
+ SPICE_DEBUG("migrating channel id:%d type:%d", id, type);
+
+ c = get_channel_by_id_and_type(s->migration, id, type);
+ g_return_if_fail(c != NULL);
+
+ spice_channel_swap(channel, c);
+ s->migration_left = g_list_remove(s->migration_left, channel);
+
+ if (g_list_length(s->migration_left) == 0) {
SPICE_DEBUG("all channel migrated");
spice_session_disconnect(s->migration);
g_object_unref(s->migration);
@@ -820,6 +881,9 @@ void spice_session_channel_destroy(SpiceSession *session, SpiceChannel *channel)
g_return_if_fail(s != NULL);
g_return_if_fail(channel != NULL);
+ if (s->migration_left)
+ s->migration_left = g_list_remove(s->migration_left, channel);
+
for (ring = ring_get_head(&s->channels); ring != NULL;
ring = next) {
next = ring_next(&s->channels, ring);