summaryrefslogtreecommitdiffstats
path: root/server/main_channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/main_channel.c')
-rw-r--r--server/main_channel.c54
1 files changed, 50 insertions, 4 deletions
diff --git a/server/main_channel.c b/server/main_channel.c
index ffc593d2..b2439b29 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -129,6 +129,8 @@ struct MainChannelClient {
#endif
int mig_wait_connect;
int mig_connect_ok;
+ int mig_wait_prev_complete;
+ int init_sent;
};
enum NetTestStage {
@@ -138,6 +140,9 @@ enum NetTestStage {
NET_TEST_STAGE_RATE,
};
+static void main_channel_release_pipe_item(RedChannelClient *rcc,
+ PipeItem *base, int item_pushed);
+
int main_channel_is_connected(MainChannel *main_chan)
{
return red_channel_is_connected(&main_chan->base);
@@ -289,6 +294,11 @@ static PipeItem *main_multi_media_time_item_new(
static void main_channel_push_channels(MainChannelClient *mcc)
{
+ if (red_client_during_migrate_at_target(mcc->base.client)) {
+ red_printf("warning: ignoring unexpected SPICE_MSGC_MAIN_ATTACH_CHANNELS"
+ "during migration");
+ return;
+ }
red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_CHANNELS_LIST);
}
@@ -451,7 +461,7 @@ static uint64_t main_channel_handle_migrate_data(RedChannelClient *base,
return TRUE;
}
-void main_channel_push_init(MainChannelClient *mcc, int connection_id,
+void main_channel_push_init(MainChannelClient *mcc,
int display_channels_hint, int current_mouse_mode,
int is_client_mouse_allowed, int multi_media_time,
int ram_hint)
@@ -459,7 +469,7 @@ void main_channel_push_init(MainChannelClient *mcc, int connection_id,
PipeItem *item;
item = main_init_item_new(mcc,
- connection_id, display_channels_hint, current_mouse_mode,
+ mcc->connection_id, display_channels_hint, current_mouse_mode,
is_client_mouse_allowed, multi_media_time, ram_hint);
red_channel_client_pipe_add_push(&mcc->base, item);
}
@@ -612,6 +622,13 @@ static void main_channel_send_item(RedChannelClient *rcc, PipeItem *base)
MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, base);
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
+ if (!mcc->init_sent && base->type != SPICE_MSG_MAIN_INIT) {
+ red_printf("Init msg for client %p was not sent yet "
+ "(client is probably during migration). Ignoring msg type %d",
+ rcc->client, base->type);
+ main_channel_release_pipe_item(rcc, base, FALSE);
+ return;
+ }
red_channel_client_init_send_data(rcc, base->type, base);
switch (base->type) {
case SPICE_MSG_MAIN_CHANNELS_LIST:
@@ -646,6 +663,7 @@ static void main_channel_send_item(RedChannelClient *rcc, PipeItem *base)
mcc->ping_id);
break;
case SPICE_MSG_MAIN_INIT:
+ mcc->init_sent = TRUE;
main_channel_marshall_init(m,
SPICE_CONTAINEROF(base, InitPipeItem, base));
break;
@@ -710,6 +728,25 @@ void main_channel_client_handle_migrate_connected(MainChannelClient *mcc, int su
}
}
+void main_channel_client_handle_migrate_end(MainChannelClient *mcc)
+{
+ if (!red_client_during_migrate_at_target(mcc->base.client)) {
+ red_printf("unexpected SPICE_MSGC_MIGRATE_END");
+ return;
+ }
+ if (!red_channel_client_test_remote_cap(&mcc->base,
+ SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE)) {
+ red_printf("unexpected SPICE_MSGC_MIGRATE_END, "
+ "client does not support semi-seamless migration");
+ return;
+ }
+ red_client_migrate_complete(mcc->base.client);
+ if (mcc->mig_wait_prev_complete) {
+ red_channel_client_pipe_add_type(&mcc->base, SPICE_MSG_MAIN_MIGRATE_BEGIN);
+ mcc->mig_wait_connect = TRUE;
+ mcc->mig_wait_prev_complete = FALSE;
+ }
+}
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);
@@ -797,6 +834,9 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
}
case SPICE_MSGC_DISCONNECTING:
break;
+ case SPICE_MSGC_MAIN_MIGRATE_END:
+ main_channel_client_handle_migrate_end(mcc);
+ break;
default:
red_printf("unexpected type %d", type);
}
@@ -989,8 +1029,13 @@ int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice *mig_ta
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;
+ if (red_client_during_migrate_at_target(mcc->base.client)) {
+ red_printf("client %p: wait till previous migration completes", mcc->base.client);
+ mcc->mig_wait_prev_complete = TRUE;
+ } else {
+ 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++;
}
@@ -1011,6 +1056,7 @@ void main_channel_migrate_cancel_wait(MainChannel *main_chan)
mcc->mig_wait_connect = FALSE;
mcc->mig_connect_ok = FALSE;
}
+ mcc->mig_wait_prev_complete = FALSE;
}
main_chan->num_clients_mig_wait = 0;
}