diff options
-rw-r--r-- | gtk/channel-main.c | 16 | ||||
-rw-r--r-- | gtk/spice-channel.c | 4 | ||||
-rw-r--r-- | gtk/spice-session-priv.h | 1 | ||||
-rw-r--r-- | gtk/spice-session.c | 104 |
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); |