[Spice-devel] [PATCH migration 07/19] server: handle spice_server_migrate_end
Alon Levy
alevy at redhat.com
Tue Nov 1 02:21:07 PDT 2011
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 <yhalperi at 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
>
More information about the Spice-devel
mailing list