On Wed, Oct 12, 2011 at 12:38:57PM +0200, Yonit Halperin wrote: > If the migration has completed successfully: > (1) send MSG_MAIN_MIGRATE_END to the clients that are connected to the target > (2) send MSG_MAIN_SWITCH_HOST to all the other clients >
ACK. > If the migration failed, send MSG_MAIN_MIGRATE_CANCEL to clients that are > connected to the target. > > (cherry picked from commit 4b82580fc36228af13db4ac3c403753d6b5c40b5 branch > 0.8; > Was modified to support multiple clients, and the separation of main_channel > from reds) > > Conflicts: > > server/reds.c > > Signed-off-by: Yonit Halperin <yhalp...@redhat.com> > --- > server/main_channel.c | 111 > +++++++++++++++++++++++++++++++------------------ > server/main_channel.h | 8 ++- > server/reds.c | 104 ++++++++++++++++++--------------------------- > server/reds.h | 2 - > 4 files changed, 117 insertions(+), 108 deletions(-) > > diff --git a/server/main_channel.c b/server/main_channel.c > index 5b16b30..ffc593d 100644 > --- a/server/main_channel.c > +++ b/server/main_channel.c > @@ -548,11 +548,6 @@ static void > main_channel_marshall_migrate(SpiceMarshaller *m) > spice_marshall_msg_migrate(m, &migrate); > } > > -void main_channel_push_migrate_cancel(MainChannel *main_chan) > -{ > - red_channel_pipes_add_type(&main_chan->base, > SPICE_MSG_MAIN_MIGRATE_CANCEL); > -} > - > void main_channel_push_multi_media_time(MainChannel *main_chan, int time) > { > MultiMediaTimePipeItem info = { > @@ -563,33 +558,43 @@ void main_channel_push_multi_media_time(MainChannel > *main_chan, int time) > main_multi_media_time_item_new, &info); > } > > -static PipeItem *main_migrate_switch_item_new(RedChannelClient *rcc, > - void *data, int num) > +static void main_channel_fill_mig_target(MainChannel *main_channel, > RedsMigSpice *mig_target) > { > - RefsPipeItem *item = spice_malloc(sizeof(*item)); > - > - item->refs = data; > - red_channel_pipe_item_init(rcc->channel, &item->base, > - SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST); > - return &item->base; > + ASSERT(mig_target); > + free(main_channel->mig_target.host); > + main_channel->mig_target.host = strdup(mig_target->host); > + free(main_channel->mig_target.cert_subject); > + if (mig_target->cert_subject) { > + main_channel->mig_target.cert_subject = > strdup(mig_target->cert_subject); > + } > + main_channel->mig_target.port = mig_target->port; > + main_channel->mig_target.sport = mig_target->sport; > } > > -void main_channel_push_migrate_switch(MainChannel *main_chan) > +void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice > *mig_target) > { > - int *refs = spice_malloc0(sizeof(int)); > - > - *refs = main_chan->base.clients_num; > - red_channel_pipes_new_add_push(&main_chan->base, > - main_migrate_switch_item_new, (void*)refs); > + main_channel_fill_mig_target(main_chan, mig_target); > + red_channel_pipes_add_type(&main_chan->base, > SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST); > } > > -static void main_channel_marshall_migrate_switch(SpiceMarshaller *m) > +static void main_channel_marshall_migrate_switch(SpiceMarshaller *m, > RedChannelClient *rcc) > { > SpiceMsgMainMigrationSwitchHost migrate; > + MainChannel *main_ch; > > red_printf(""); > - > - reds_fill_mig_switch(&migrate); > + main_ch = SPICE_CONTAINEROF(rcc->channel, MainChannel, base); > + migrate.port = main_ch->mig_target.port; > + migrate.sport = main_ch->mig_target.sport; > + migrate.host_size = strlen(main_ch->mig_target.host) + 1; > + migrate.host_data = (uint8_t *)main_ch->mig_target.host; > + if (main_ch->mig_target.cert_subject) { > + migrate.cert_subject_size = strlen(main_ch->mig_target.cert_subject) > + 1; > + migrate.cert_subject_data = (uint8_t > *)main_ch->mig_target.cert_subject; > + } else { > + migrate.cert_subject_size = 0; > + migrate.cert_subject_data = NULL; > + } > spice_marshall_msg_main_migrate_switch_host(m, &migrate); > } > > @@ -659,7 +664,7 @@ static void main_channel_send_item(RedChannelClient *rcc, > PipeItem *base) > SPICE_CONTAINEROF(base, MultiMediaTimePipeItem, base)); > break; > case SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST: > - main_channel_marshall_migrate_switch(m); > + main_channel_marshall_migrate_switch(m, rcc); > break; > }; > red_channel_client_begin_send_message(rcc); > @@ -679,14 +684,6 @@ static void > main_channel_release_pipe_item(RedChannelClient *rcc, > } > break; > } > - case SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST: { > - RefsPipeItem *data = (RefsPipeItem*)base; > - if (!--*(data->refs)) { > - free(data->refs); > - reds_mig_release(); > - } > - break; > - } > default: > break; > } > @@ -985,16 +982,7 @@ int main_channel_migrate_connect(MainChannel > *main_channel, RedsMigSpice *mig_ta > { > RingItem *client_link; > > - ASSERT(mig_target); > - free(main_channel->mig_target.host); > - main_channel->mig_target.host = strdup(mig_target->host); > - free(main_channel->mig_target.cert_subject); > - if (mig_target->cert_subject) { > - main_channel->mig_target.cert_subject = > strdup(mig_target->cert_subject); > - } > - main_channel->mig_target.port = mig_target->port; > - main_channel->mig_target.sport = mig_target->sport; > - > + main_channel_fill_mig_target(main_channel, mig_target); > main_channel->num_clients_mig_wait = 0; > > RING_FOREACH(client_link, &main_channel->base.clients) { > @@ -1026,3 +1014,44 @@ void main_channel_migrate_cancel_wait(MainChannel > *main_chan) > } > main_chan->num_clients_mig_wait = 0; > } > + > +int main_channel_migrate_complete(MainChannel *main_chan, int success) > +{ > + RingItem *client_link; > + int semi_seamless_count = 0; > + > + red_printf(""); > + > + if (ring_is_empty(&main_chan->base.clients)) { > + red_printf("no peer connected"); > + return 0; > + } > + > + RING_FOREACH(client_link, &main_chan->base.clients) { > + MainChannelClient *mcc; > + int semi_seamless_support; > + > + mcc = SPICE_CONTAINEROF(client_link, MainChannelClient, > base.channel_link); > + semi_seamless_support = > red_channel_client_test_remote_cap(&mcc->base, > + > SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE); > + if (semi_seamless_support && mcc->mig_connect_ok) { > + if (success) { > + red_printf("client %p MIGRATE_END", mcc->base.client); > + red_channel_client_pipe_add_type(&mcc->base, > SPICE_MSG_MAIN_MIGRATE_END); > + semi_seamless_count++; > + } else { > + red_printf("client %p MIGRATE_CANCEL", mcc->base.client); > + red_channel_client_pipe_add_type(&mcc->base, > SPICE_MSG_MAIN_MIGRATE_CANCEL); > + } > + } else { > + if (success) { > + red_printf("client %p SWITCH_HOST", mcc->base.client); > + red_channel_client_pipe_add_type(&mcc->base, > SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST); > + } > + } > + mcc->mig_connect_ok = FALSE; > + mcc->mig_wait_connect = FALSE; > + } > + return semi_seamless_count; > +} > + > diff --git a/server/main_channel.h b/server/main_channel.h > index f3702e7..d97857d 100644 > --- a/server/main_channel.h > +++ b/server/main_channel.h > @@ -83,8 +83,6 @@ void main_channel_push_init(MainChannelClient *mcc, int > connection_id, int displ > int ram_hint); > void main_channel_push_notify(MainChannel *main_chan, uint8_t *mess, const > int mess_len); > void main_channel_push_migrate(MainChannel *main_chan); > -void main_channel_push_migrate_switch(MainChannel *main_chan); > -void main_channel_push_migrate_cancel(MainChannel *main_chan); > void main_channel_push_multi_media_time(MainChannel *main_chan, int time); > int main_channel_getsockname(MainChannel *main_chan, struct sockaddr *sa, > socklen_t *salen); > int main_channel_getpeername(MainChannel *main_chan, struct sockaddr *sa, > socklen_t *salen); > @@ -95,10 +93,14 @@ uint64_t > main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc); > int main_channel_is_connected(MainChannel *main_chan); > RedChannelClient* main_channel_client_get_base(MainChannelClient* mcc); > > +/* switch host migration */ > +void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice > *mig_target); > + > /* semi seamless migration */ > > /* returns the number of clients that we are waiting for their connection */ > int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice > *mig_target); > void main_channel_migrate_cancel_wait(MainChannel *main_chan); > -void main_channel_migrate_complete(MainChannel *main_chan, int success); > +/* returns the number of clients for which SPICE_MSG_MAIN_MIGRATE_END was > sent*/ > +int main_channel_migrate_complete(MainChannel *main_chan, int success); > #endif > diff --git a/server/reds.c b/server/reds.c > index 009ad21..20032a9 100644 > --- a/server/reds.c > +++ b/server/reds.c > @@ -204,6 +204,7 @@ typedef struct RedsState { > int mig_wait_connect; > int mig_wait_disconnect; > int mig_inprogress; > + int expect_migrate; > int mig_target; > RedsMigSpice *mig_spice; > int num_of_channels; > @@ -2982,7 +2983,7 @@ typedef struct RedsMigCertPubKeyInfo { > uint32_t len; > } RedsMigCertPubKeyInfo; > > -void reds_mig_release(void) > +static void reds_mig_release(void) > { > if (reds->mig_spice) { > free(reds->mig_spice->cert_subject); > @@ -2997,29 +2998,14 @@ static void reds_mig_started(void) > red_printf(""); > ASSERT(reds->mig_spice); > > - reds->mig_wait_connect = TRUE; > reds->mig_inprogress = TRUE; > - > - if (reds->listen_watch != NULL) { > - core->watch_update_mask(reds->listen_watch, 0); > - } > - > - if (reds->secure_listen_watch != NULL) { > - core->watch_update_mask(reds->secure_listen_watch, 0); > - } > + reds->mig_wait_connect = TRUE; > core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT); > } > > static void reds_mig_finished(int completed) > { > red_printf(""); > - if (reds->listen_watch != NULL) { > - core->watch_update_mask(reds->listen_watch, SPICE_WATCH_EVENT_READ); > - } > - > - if (reds->secure_listen_watch != NULL) { > - core->watch_update_mask(reds->secure_listen_watch, > SPICE_WATCH_EVENT_READ); > - } > > if (!reds_main_channel_connected()) { > red_printf("no peer connected"); > @@ -3027,28 +3013,13 @@ static void reds_mig_finished(int completed) > } > reds->mig_inprogress = TRUE; > > - if (completed) { > - RingItem *link, *next; > - > + if (main_channel_migrate_complete(reds->main_channel, completed)) { > reds->mig_wait_disconnect = TRUE; > core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT); > - > - // TODO: so now that main channel is separate, how exactly does > migration of it work? > - // - it can have an empty migrate - that seems ok > - // - I can try to fill it's migrate, then move stuff from reds.c > there, but a lot of data > - // is in reds state right now. > - // currently the migrate callback of main_channel does nothing > - main_channel_push_migrate(reds->main_channel); > - > - RING_FOREACH_SAFE(link, next, &reds->clients) { > - red_client_migrate(SPICE_CONTAINEROF(link, RedClient, link)); > - } > } else { > - main_channel_push_migrate_cancel(reds->main_channel); > - // TODO: all the seemless migration is broken. Before MC we waited > for disconection of one client, > - // no we need to wait to all the clients (see mig_timer)? > reds_mig_cleanup(); > } > + reds_mig_release(); > } > > static void reds_mig_switch(void) > @@ -3057,30 +3028,8 @@ static void reds_mig_switch(void) > red_printf("warning: reds_mig_switch called without migrate_info > set"); > return; > } > - main_channel_push_migrate_switch(reds->main_channel); > -} > - > -void reds_fill_mig_switch(SpiceMsgMainMigrationSwitchHost *migrate) > -{ > - RedsMigSpice *s = reds->mig_spice; > - > - if (s == NULL) { > - red_printf( > - "error: reds_fill_mig_switch called without migrate info set"); > - bzero(migrate, sizeof(*migrate)); > - return; > - } > - migrate->port = s->port; > - migrate->sport = s->sport; > - migrate->host_size = strlen(s->host) + 1; > - migrate->host_data = (uint8_t *)s->host; > - if (s->cert_subject) { > - migrate->cert_subject_size = strlen(s->cert_subject) + 1; > - migrate->cert_subject_data = (uint8_t *)s->cert_subject; > - } else { > - migrate->cert_subject_size = 0; > - migrate->cert_subject_data = NULL; > - } > + main_channel_migrate_switch(reds->main_channel, reds->mig_spice); > + reds_mig_release(); > } > > static void migrate_timeout(void *opaque) > @@ -3871,6 +3820,11 @@ SPICE_GNUC_VISIBLE int > spice_server_migrate_connect(SpiceServer *s, const char* > ASSERT(migration_interface); > ASSERT(reds == s); > > + if (reds->expect_migrate) { > + red_printf("warning: consecutive calls without migration. Canceling > previous call"); > + main_channel_migrate_complete(reds->main_channel, FALSE); > + } > + > sif = SPICE_CONTAINEROF(migration_interface->base.sif, > SpiceMigrateInterface, base); > > if (!reds_set_migration_dest_info(dest, port, secure_port, > cert_subject)) { > @@ -3878,10 +3832,16 @@ SPICE_GNUC_VISIBLE int > spice_server_migrate_connect(SpiceServer *s, const char* > return -1; > } > > + reds->expect_migrate = TRUE; > + > + > if (main_channel_migrate_connect(reds->main_channel, reds->mig_spice)) { > - reds->mig_wait_connect = TRUE; > reds_mig_started(); > } else { > + if (reds->num_clients == 0) { > + reds_mig_release(); > + red_printf("no client connected"); > + } > sif->migrate_connect_complete(migration_interface); > } > > @@ -3892,13 +3852,13 @@ SPICE_GNUC_VISIBLE int > spice_server_migrate_info(SpiceServer *s, const char* des > int port, int secure_port, > const char* cert_subject) > { > + red_printf(""); > ASSERT(!migration_interface); > ASSERT(reds == s); > > if (!reds_set_migration_dest_info(dest, port, secure_port, > cert_subject)) { > return -1; > } > - > return 0; > } > > @@ -3935,20 +3895,40 @@ SPICE_GNUC_VISIBLE int > spice_server_migrate_client_state(SpiceServer *s) > SPICE_GNUC_VISIBLE int spice_server_migrate_end(SpiceServer *s, int > completed) > { > SpiceMigrateInterface *sif; > + int ret = 0; > + > + red_printf(""); > + > ASSERT(migration_interface); > ASSERT(reds == s); > - reds_mig_finished(completed); > + > sif = SPICE_CONTAINEROF(migration_interface->base.sif, > SpiceMigrateInterface, base); > + if (!reds->expect_migrate && reds->num_clients) { > + red_printf("spice_server_migrate_info was not called, disconnecting > clients"); > + reds_disconnect(); > + ret = -1; > + goto complete; > + } > + > + reds->expect_migrate = FALSE; > + reds_mig_finished(completed); > + ret = 0; > +complete: > if (sif->migrate_end_complete) { > sif->migrate_end_complete(migration_interface); > } > - return 0; > + return ret; > } > > /* interface for switch-host migration */ > SPICE_GNUC_VISIBLE int spice_server_migrate_switch(SpiceServer *s) > { > ASSERT(reds == s); > + red_printf(""); > + if (!reds->num_clients) { > + return 0; > + } > + reds->expect_migrate = FALSE; > reds_mig_switch(); > return 0; > } > diff --git a/server/reds.h b/server/reds.h > index 13fec42..9feb9ab 100644 > --- a/server/reds.h > +++ b/server/reds.h > @@ -133,8 +133,6 @@ void reds_client_disconnect(RedClient *client); > typedef struct MainMigrateData MainMigrateData; > void reds_marshall_migrate_data_item(SpiceMarshaller *m, MainMigrateData > *data); > void reds_fill_channels(SpiceMsgChannels *channels_info); > -void reds_fill_mig_switch(SpiceMsgMainMigrationSwitchHost *migrate); > -void reds_mig_release(void); > int reds_num_of_channels(void); > int reds_num_of_clients(void); > #ifdef RED_STATISTICS > -- > 1.7.6.4 > _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel