On Wed, Oct 12, 2011 at 12:38:55PM +0200, Yonit Halperin wrote: > (1) send SPICE_MSG_MAIN_MIGRATE_BEGIN upon spice_server_migrate_connect > (to all the clients that support it) > (2) wait for SPICE_MSGC_MAIN_MIGRATE_(CONNECTED|CONNECT_ERROR) from all the > relevant clients, > or a timeout, in order to complete client_migrate_info monitor command > (cherry picked from commit 5560c56ef05c74da5e0e0825dc1f134019593cad branch > 0.8; > Was modified to support the separation of main channel from reds, and > multiple clients) >
Looks ok. ACK. > Conflicts: > > server/reds.c > > Signed-off-by: Yonit Halperin <yhalp...@redhat.com> > --- > common/messages.h | 2 + > server/main_channel.c | 164 > ++++++++++++++++++++++++++++--------------------- > server/main_channel.h | 12 +++- > server/red_channel.h | 2 +- > server/reds.c | 129 +++++++++++++++++--------------------- > server/reds.h | 14 +++- > spice.proto | 5 +- > 7 files changed, 176 insertions(+), 152 deletions(-) > > diff --git a/common/messages.h b/common/messages.h > index 8151dc0..a54190f 100644 > --- a/common/messages.h > +++ b/common/messages.h > @@ -66,6 +66,8 @@ typedef struct SpiceMsgMainMigrationBegin { > uint16_t pub_key_type; > uint32_t pub_key_size; > uint8_t *pub_key_data; > + uint32_t cert_subject_size; > + uint8_t *cert_subject_data; > } SpiceMsgMainMigrationBegin; > > typedef struct SpiceMsgMainMigrationSwitchHost { > diff --git a/server/main_channel.c b/server/main_channel.c > index 49028b3..5b16b30 100644 > --- a/server/main_channel.c > +++ b/server/main_channel.c > @@ -110,16 +110,6 @@ typedef struct NotifyPipeItem { > int mess_len; > } NotifyPipeItem; > > -typedef struct MigrateBeginPipeItem { > - PipeItem base; > - int port; > - int sport; > - char *host; > - uint16_t cert_pub_key_type; > - uint32_t cert_pub_key_len; > - uint8_t *cert_pub_key; > -} MigrateBeginPipeItem; > - > typedef struct MultiMediaTimePipeItem { > PipeItem base; > int time; > @@ -137,6 +127,8 @@ struct MainChannelClient { > SpiceTimer *ping_timer; > int ping_interval; > #endif > + int mig_wait_connect; > + int mig_connect_ok; > }; > > enum NetTestStage { > @@ -283,33 +275,6 @@ static PipeItem *main_notify_item_new(RedChannelClient > *rcc, void *data, int num > return &item->base; > } > > -typedef struct MigrateBeginItemInfo { > - int port; > - int sport; > - char *host; > - uint16_t cert_pub_key_type; > - uint32_t cert_pub_key_len; > - uint8_t *cert_pub_key; > -} MigrateBeginItemInfo; > - > -// TODO: MC: migration is not tested at all with multiclient. > -static PipeItem *main_migrate_begin_item_new( > - RedChannelClient *rcc, void *data, int num) > -{ > - MigrateBeginPipeItem *item = spice_malloc(sizeof(MigrateBeginPipeItem)); > - MigrateBeginItemInfo *info = data; > - > - red_channel_pipe_item_init(rcc->channel, &item->base, > - SPICE_MSG_MAIN_MIGRATE_BEGIN); > - item->port = info->port; > - item->sport = info->sport; > - item->host = info->host; > - item->cert_pub_key_type = info->cert_pub_key_type; > - item->cert_pub_key_len = info->cert_pub_key_len; > - item->cert_pub_key = info->cert_pub_key; > - return &item->base; > -} > - > static PipeItem *main_multi_media_time_item_new( > RedChannelClient *rcc, void *data, int num) > { > @@ -550,35 +515,23 @@ static void > main_channel_marshall_notify(SpiceMarshaller *m, NotifyPipeItem *ite > spice_marshaller_add(m, item->mess, item->mess_len + 1); > } > > -void main_channel_push_migrate_begin(MainChannel *main_chan, int port, int > sport, > - char *host, uint16_t cert_pub_key_type, uint32_t cert_pub_key_len, > - uint8_t *cert_pub_key) > -{ > - MigrateBeginItemInfo info = { > - .port =port, > - .sport = sport, > - .host = host, > - .cert_pub_key_type = cert_pub_key_type, > - .cert_pub_key_len = cert_pub_key_len, > - .cert_pub_key = cert_pub_key, > - }; > - > - red_channel_pipes_new_add_push(&main_chan->base, > - main_migrate_begin_item_new, &info); > -} > - > -static void main_channel_marshall_migrate_begin(SpiceMarshaller *m, > - MigrateBeginPipeItem *item) > +static void main_channel_marshall_migrate_begin(SpiceMarshaller *m, > RedChannelClient *rcc) > { > SpiceMsgMainMigrationBegin migrate; > - > - migrate.port = item->port; > - migrate.sport = item->sport; > - migrate.host_size = strlen(item->host) + 1; > - migrate.host_data = (uint8_t *)item->host; > - migrate.pub_key_type = item->cert_pub_key_type; > - migrate.pub_key_size = item->cert_pub_key_len; > - migrate.pub_key_data = item->cert_pub_key; > + MainChannel *main_ch; > + > + 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_begin(m, &migrate); > } > > @@ -699,8 +652,7 @@ static void main_channel_send_item(RedChannelClient *rcc, > PipeItem *base) > main_channel_marshall_migrate(m); > break; > case SPICE_MSG_MAIN_MIGRATE_BEGIN: > - main_channel_marshall_migrate_begin(m, > - SPICE_CONTAINEROF(base, MigrateBeginPipeItem, base)); > + main_channel_marshall_migrate_begin(m, rcc); > break; > case SPICE_MSG_MAIN_MULTI_MEDIA_TIME: > main_channel_marshall_multi_media_time(m, > @@ -741,6 +693,26 @@ static void > main_channel_release_pipe_item(RedChannelClient *rcc, > free(base); > } > > +void main_channel_client_handle_migrate_connected(MainChannelClient *mcc, > int success) > +{ > + red_printf("client %p connected: %d", mcc->base.client, success); > + if (mcc->mig_wait_connect) { > + MainChannel *main_channel = SPICE_CONTAINEROF(mcc->base.channel, > MainChannel, base); > + > + mcc->mig_wait_connect = FALSE; > + mcc->mig_connect_ok = success; > + ASSERT(main_channel->num_clients_mig_wait); > + if (!--main_channel->num_clients_mig_wait) { > + reds_on_main_migrate_connected(); > + } > + } else { > + if (success) { > + red_printf("client %p MIGRATE_CANCEL", mcc->base.client); > + red_channel_client_pipe_add_type(&mcc->base, > SPICE_MSG_MAIN_MIGRATE_CANCEL); > + } > + } > +} > + > static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, > uint16_t type, void *message) > { > MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, > base); > @@ -764,12 +736,10 @@ static int main_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, uint > main_channel_push_channels(mcc); > break; > case SPICE_MSGC_MAIN_MIGRATE_CONNECTED: > - red_printf("connected"); > - reds_on_main_migrate_connected(); > + main_channel_client_handle_migrate_connected(mcc, TRUE); > break; > case SPICE_MSGC_MAIN_MIGRATE_CONNECT_ERROR: > - red_printf("mig connect error"); > - reds_on_main_migrate_connect_error(); > + main_channel_client_handle_migrate_connected(mcc, FALSE); > break; > case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST: > reds_on_main_mouse_mode_request(message, size); > @@ -1001,6 +971,58 @@ MainChannel* main_channel_init(void) > main_channel_handle_parsed, > &channel_cbs); > ASSERT(channel); > - > + red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE); > return (MainChannel *)channel; > } > + > +RedChannelClient* main_channel_client_get_base(MainChannelClient* mcc) > +{ > + ASSERT(mcc); > + return &mcc->base; > +} > + > +int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice > *mig_target) > +{ > + 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->num_clients_mig_wait = 0; > + > + RING_FOREACH(client_link, &main_channel->base.clients) { > + MainChannelClient * mcc = SPICE_CONTAINEROF(client_link, > MainChannelClient, base.channel_link); > + if (red_channel_client_test_remote_cap(&mcc->base, > + > SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE)) { > + red_channel_client_pipe_add_type(&mcc->base, > SPICE_MSG_MAIN_MIGRATE_BEGIN); > + mcc->mig_wait_connect = TRUE; > + mcc->mig_connect_ok = FALSE; > + main_channel->num_clients_mig_wait++; > + } > + } > + return main_channel->num_clients_mig_wait; > +} > + > +void main_channel_migrate_cancel_wait(MainChannel *main_chan) > +{ > + RingItem *client_link; > + > + RING_FOREACH(client_link, &main_chan->base.clients) { > + MainChannelClient *mcc; > + > + mcc = SPICE_CONTAINEROF(client_link, MainChannelClient, > base.channel_link); > + if (mcc->mig_wait_connect) { > + red_printf("client %p cancel wait connect", mcc->base.client); > + mcc->mig_wait_connect = FALSE; > + mcc->mig_connect_ok = FALSE; > + } > + } > + main_chan->num_clients_mig_wait = 0; > +} > diff --git a/server/main_channel.h b/server/main_channel.h > index 2ae05e8..f3702e7 100644 > --- a/server/main_channel.h > +++ b/server/main_channel.h > @@ -57,6 +57,8 @@ struct MainMigrateData { > typedef struct MainChannel { > RedChannel base; > uint8_t recv_buf[RECEIVE_BUF_SIZE]; > + RedsMigSpice mig_target; // TODO: add refs and release (afrer all > clients completed migration in one way or the other?) > + int num_clients_mig_wait; > } MainChannel; > > > @@ -80,9 +82,6 @@ void main_channel_push_init(MainChannelClient *mcc, int > connection_id, int displ > int current_mouse_mode, int is_client_mouse_allowed, int > multi_media_time, > int ram_hint); > void main_channel_push_notify(MainChannel *main_chan, uint8_t *mess, const > int mess_len); > -// TODO: consider exporting RedsMigSpice from reds.c > -void main_channel_push_migrate_begin(MainChannel *main_chan, int port, int > sport, char *host, > - uint16_t cert_pub_key_type, uint32_t cert_pub_key_len, uint8_t > *cert_pub_key); > 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); > @@ -94,5 +93,12 @@ uint32_t main_channel_client_get_link_id(MainChannelClient > *mcc); > int main_channel_client_is_low_bandwidth(MainChannelClient *mcc); > 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); > > +/* 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); > #endif > diff --git a/server/red_channel.h b/server/red_channel.h > index d044253..e30401c 100644 > --- a/server/red_channel.h > +++ b/server/red_channel.h > @@ -450,6 +450,7 @@ struct RedClient { > pthread_t thread_id; > > int disconnecting; > + > }; > > RedClient *red_client_new(void); > @@ -457,7 +458,6 @@ MainChannelClient *red_client_get_main(RedClient *client); > // main should be set once before all the other channels are created > void red_client_set_main(RedClient *client, MainChannelClient *mcc); > > - > void red_client_migrate(RedClient *client); > // disconnects all the client's channels (should be called from the client's > thread) > void red_client_destroy(RedClient *client); > diff --git a/server/reds.c b/server/reds.c > index 40b54bb..009ad21 100644 > --- a/server/reds.c > +++ b/server/reds.c > @@ -190,8 +190,6 @@ typedef struct RedsStatValue { > > #endif > > -typedef struct RedsMigSpice RedsMigSpice; > - > typedef struct RedsState { > int listen_socket; > int secure_listen_socket; > @@ -294,6 +292,7 @@ struct ChannelSecurityOptions { > ChannelSecurityOptions *next; > }; > > +static void migrate_timeout(void *opaque); > > static ChannelSecurityOptions *channels_security = NULL; > static int default_channel_security = > @@ -537,6 +536,12 @@ static RedChannel *reds_find_channel(uint32_t type, > uint32_t id) > static void reds_mig_cleanup(void) > { > if (reds->mig_inprogress) { > + if (reds->mig_wait_connect) { > + SpiceMigrateInterface *sif; > + ASSERT(migration_interface); > + sif = SPICE_CONTAINEROF(migration_interface->base.sif, > SpiceMigrateInterface, base); > + sif->migrate_connect_complete(migration_interface); > + } > reds->mig_inprogress = FALSE; > reds->mig_wait_connect = FALSE; > reds->mig_wait_disconnect = FALSE; > @@ -1059,13 +1064,6 @@ void reds_on_main_migrate_connected(void) > } > } > > -void reds_on_main_migrate_connect_error(void) > -{ > - if (reds->mig_wait_connect) { > - reds_mig_cleanup(); > - } > -} > - > void reds_on_main_mouse_mode_request(void *message, size_t size) > { > switch (((SpiceMsgcMainMouseModeRequest *)message)->mode) { > @@ -2975,18 +2973,6 @@ static void set_one_channel_security(int id, uint32_t > security) > > #define REDS_SAVE_VERSION 1 > > -struct RedsMigSpice { > - char pub_key[SPICE_TICKET_PUBKEY_BYTES]; > - uint32_t mig_key; > - char *host; > - char *cert_subject; > - int port; > - int sport; > - uint16_t cert_pub_key_type; > - uint32_t cert_pub_key_len; > - uint8_t* cert_pub_key; > -}; > - > typedef struct RedsMigSpiceMessage { > uint32_t connection_id; > } RedsMigSpiceMessage; > @@ -3006,24 +2992,12 @@ void reds_mig_release(void) > } > } > > -static void reds_mig_continue(void) > -{ > - RedsMigSpice *s = reds->mig_spice; > - > - red_printf(""); > - main_channel_push_migrate_begin(reds->main_channel, s->port, s->sport, > - s->host, s->cert_pub_key_type, s->cert_pub_key_len, s->cert_pub_key); > - > - reds_mig_release(); > - > - reds->mig_wait_connect = TRUE; > - core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT); > -} > - > 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) { > @@ -3033,24 +3007,7 @@ static void reds_mig_started(void) > if (reds->secure_listen_watch != NULL) { > core->watch_update_mask(reds->secure_listen_watch, 0); > } > - > - if (!reds_main_channel_connected()) { > - red_printf("not connected to peer"); > - goto error; > - } > - > - if ((SPICE_VERSION_MAJOR == 1) && (reds->peer_minor_version < 2)) { > - red_printf("minor version mismatch client %u server %u", > - reds->peer_minor_version, SPICE_VERSION_MINOR); > - goto error; > - } > - > - reds_mig_continue(); > - return; > - > -error: > - reds_mig_release(); > - reds_mig_disconnect(); > + core->timer_start(reds->mig_timer, MIGRATE_TIMEOUT); > } > > static void reds_mig_finished(int completed) > @@ -3126,11 +3083,16 @@ void > reds_fill_mig_switch(SpiceMsgMainMigrationSwitchHost *migrate) > } > } > > -static void migrate_timout(void *opaque) > +static void migrate_timeout(void *opaque) > { > red_printf(""); > ASSERT(reds->mig_wait_connect || reds->mig_wait_disconnect); > - reds_mig_disconnect(); > + if (reds->mig_wait_connect) { > + main_channel_migrate_cancel_wait(reds->main_channel); > + reds_mig_cleanup(); > + } else { > + reds_mig_disconnect(); > + } > } > > uint32_t reds_get_mm_time(void) > @@ -3490,7 +3452,7 @@ static int do_spice_init(SpiceCoreInterface > *core_interface) > reds->num_clients = 0; > ring_init(&reds->channels); > > - if (!(reds->mig_timer = core->timer_add(migrate_timout, NULL))) { > + if (!(reds->mig_timer = core->timer_add(migrate_timeout, NULL))) { > red_error("migration timer create failed"); > } > if (!(reds->vdi_port_write_timer = core->timer_add(vdi_port_write_retry, > NULL))) > @@ -3873,19 +3835,55 @@ SPICE_GNUC_VISIBLE int > spice_server_set_agent_copypaste(SpiceServer *s, int enab > return 0; > } > > +/* returns FALSE if info is invalid */ > +static int reds_set_migration_dest_info(const char* dest, > + int port, int secure_port, > + const char* cert_subject) > +{ > + RedsMigSpice *spice_migration = NULL; > + > + reds_mig_release(); > + if ((port == -1 && secure_port == -1) || !dest) { > + return FALSE; > + } > + > + spice_migration = spice_new0(RedsMigSpice, 1); > + spice_migration->port = port; > + spice_migration->sport = secure_port; > + spice_migration->host = strdup(dest); > + if (cert_subject) { > + spice_migration->cert_subject = strdup(cert_subject); > + } > + > + reds->mig_spice = spice_migration; > + > + return TRUE; > +} > + > /* semi-seamless client migration */ > SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *s, const > char* dest, > int port, int > secure_port, > const char* cert_subject) > { > SpiceMigrateInterface *sif; > + > red_printf(""); > ASSERT(migration_interface); > ASSERT(reds == s); > > - red_printf("not implemented yet"); > sif = SPICE_CONTAINEROF(migration_interface->base.sif, > SpiceMigrateInterface, base); > - sif->migrate_connect_complete(migration_interface); > + > + if (!reds_set_migration_dest_info(dest, port, secure_port, > cert_subject)) { > + sif->migrate_connect_complete(migration_interface); > + return -1; > + } > + > + if (main_channel_migrate_connect(reds->main_channel, reds->mig_spice)) { > + reds->mig_wait_connect = TRUE; > + reds_mig_started(); > + } else { > + sif->migrate_connect_complete(migration_interface); > + } > > return 0; > } > @@ -3894,27 +3892,16 @@ SPICE_GNUC_VISIBLE int > spice_server_migrate_info(SpiceServer *s, const char* des > int port, int secure_port, > const char* cert_subject) > { > - RedsMigSpice *spice_migration = NULL; > - > + ASSERT(!migration_interface); > ASSERT(reds == s); > > - if ((port == -1 && secure_port == -1) || !dest) > + if (!reds_set_migration_dest_info(dest, port, secure_port, > cert_subject)) { > return -1; > - > - spice_migration = spice_new0(RedsMigSpice, 1); > - spice_migration->port = port; > - spice_migration->sport = secure_port; > - spice_migration->host = strdup(dest); > - if (cert_subject) { > - spice_migration->cert_subject = strdup(cert_subject); > } > > - reds_mig_release(); > - reds->mig_spice = spice_migration; > return 0; > } > > -/* interface for seamless migration */ > SPICE_GNUC_VISIBLE int spice_server_migrate_start(SpiceServer *s) > { > ASSERT(reds == s); > diff --git a/server/reds.h b/server/reds.h > index 7720b30..13fec42 100644 > --- a/server/reds.h > +++ b/server/reds.h > @@ -99,6 +99,13 @@ struct SpiceMigrateState { > int dummy; > }; > > +typedef struct RedsMigSpice { > + char *host; > + char *cert_subject; > + int port; > + int sport; > +} RedsMigSpice; > + > ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte); > ssize_t reds_stream_write(RedsStream *s, const void *buf, size_t nbyte); > ssize_t reds_stream_writev(RedsStream *s, const struct iovec *iov, int > iovcnt); > @@ -134,11 +141,12 @@ int reds_num_of_clients(void); > void reds_update_stat_value(uint32_t value); > #endif > > -// callbacks from main channel messages > +/* callbacks from main channel messages */ > + > void reds_on_main_agent_start(void); > void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t > size); > -void reds_on_main_migrate_connected(void); > -void reds_on_main_migrate_connect_error(void); > +void reds_on_main_migrate_connected(void); //should be called when all the > clients > + // are connected to the target > void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end); > void reds_on_main_mouse_mode_request(void *message, size_t size); > > diff --git a/spice.proto b/spice.proto > index abf3ec3..78c1fad 100644 > --- a/spice.proto > +++ b/spice.proto > @@ -167,9 +167,8 @@ channel MainChannel : BaseChannel { > uint16 sport; > uint32 host_size; > uint8 *host_data[host_size] @zero_terminated @marshall @nonnull; > - pubkey_type pub_key_type; > - uint32 pub_key_size; > - uint8 *pub_key_data[pub_key_size] @zero_terminated @marshall @nonnull; > + uint32 cert_subject_size; > + uint8 *cert_subject_data[cert_subject_size] @zero_terminated @marshall; > } @ctype(SpiceMsgMainMigrationBegin) migrate_begin = 101; > > Empty migrate_cancel; > -- > 1.7.6.4 > _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel