[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