From fa9bfd01f182b34ceb8ff30ae730577cd64965cc Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Sun, 5 Aug 2012 16:57:21 +0300 Subject: main: send migration data Also removed some unused definitions from reds that used to belong to old agent and migration code. --- server/main_channel.c | 14 ++----- server/reds.c | 102 ++++++++++++++++++++++++++++++++++++++++++++------ server/reds.h | 2 +- 3 files changed, 95 insertions(+), 23 deletions(-) diff --git a/server/main_channel.c b/server/main_channel.c index 6cdbc4dd..0c31c88e 100644 --- a/server/main_channel.c +++ b/server/main_channel.c @@ -496,13 +496,8 @@ static void main_channel_push_migrate_data_item(MainChannel *main_chan) static void main_channel_marshall_migrate_data_item(RedChannelClient *rcc, SpiceMarshaller *m, PipeItem *item) { - MainMigrateData *data = (MainMigrateData *) - spice_marshaller_reserve_space(m, sizeof(MainMigrateData)); - red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item); - reds_marshall_migrate_data_item(m, data); // TODO: from reds split. ugly separation. - data->serial = red_channel_client_get_message_serial(rcc); - data->ping_id = SPICE_CONTAINEROF(rcc, MainChannelClient, base)->ping_id; + reds_marshall_migrate_data(m); // TODO: from reds split. ugly separation. } static uint64_t main_channel_handle_migrate_data_get_serial(RedChannelClient *base, @@ -996,17 +991,13 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint #endif break; } - case SPICE_MSGC_MIGRATE_FLUSH_MARK: - break; - case SPICE_MSGC_MIGRATE_DATA: { - } case SPICE_MSGC_DISCONNECTING: break; case SPICE_MSGC_MAIN_MIGRATE_END: main_channel_client_handle_migrate_end(mcc); break; default: - spice_printerr("unexpected type %d", type); + return red_channel_client_handle_message(rcc, size, type, message); } return TRUE; } @@ -1046,6 +1037,7 @@ static void main_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item) static int main_channel_handle_migrate_flush_mark(RedChannelClient *rcc) { + spice_debug(NULL); main_channel_push_migrate_data_item(SPICE_CONTAINEROF(rcc->channel, MainChannel, base)); return TRUE; diff --git a/server/reds.c b/server/reds.c index 1deceb42..40426e85 100644 --- a/server/reds.c +++ b/server/reds.c @@ -123,8 +123,6 @@ int agent_copypaste = TRUE; #define MIGRATE_TIMEOUT (1000 * 10) /* 10sec */ #define MM_TIMER_GRANULARITY_MS (1000 / 30) #define MM_TIME_DELTA 400 /*ms*/ -#define VDI_PORT_WRITE_RETRY_TIMEOUT 100 /*ms*/ - typedef struct TicketAuthentication { char password[SPICE_MAX_PASSWORD_LENGTH]; @@ -166,6 +164,7 @@ enum { typedef struct VDIPortState { SpiceCharDeviceState *base; uint32_t plug_generation; + int client_agent_started; /* write to agent */ SpiceCharDeviceWriteBuffer *recv_from_client_buf; @@ -635,6 +634,7 @@ static void reds_reset_vdp(void) messages written by the client */ state->write_filter.result = AGENT_MSG_FILTER_DISCARD; state->write_filter.discard_all = TRUE; + state->client_agent_started = FALSE; /* reseting and not destroying the state as a workaround for a bad * tokens management in the vdagent protocol: @@ -1097,6 +1097,7 @@ void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens) } spice_assert(vdagent->st && vdagent->st == dev_state); rcc = main_channel_client_get_base(mcc); + reds->agent_state.client_agent_started = TRUE; /* * Note that in older releases, send_tokens were set to ~0 on both client * and server. The server ignored the client given tokens. @@ -1263,16 +1264,83 @@ void reds_on_main_channel_migrate(MainChannelClient *mcc) } } -#define MAIN_CHANNEL_MIG_DATA_VERSION 1 +void reds_marshall_migrate_data(SpiceMarshaller *m) +{ + SpiceMigrateDataMain mig_data; + VDIPortState *agent_state = &reds->agent_state; + SpiceMarshaller *m2; -typedef struct WriteQueueInfo { - uint32_t port; - uint32_t len; -} WriteQueueInfo; + memset(&mig_data, 0, sizeof(mig_data)); + spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_MAIN_MAGIC); + spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_MAIN_VERSION); -void reds_marshall_migrate_data_item(SpiceMarshaller *m, MainMigrateData *data) -{ - spice_warning("not implemented"); + if (!vdagent) { + spice_assert(!agent_state->base); /* MSG_AGENT_CONNECTED_TOKENS is supported by the client + (see spice_server_migrate_connect), so SpiceCharDeviceState + is destroyed when the agent is disconnected and + there is no need to track the client tokens + (see reds_reset_vdp) */ + spice_char_device_state_migrate_data_marshall_empty(m); + spice_marshaller_add_ref(m, + (uint8_t *)&mig_data + sizeof(SpiceMigrateDataCharDevice), + sizeof(SpiceMigrateDataMain) - sizeof(SpiceMigrateDataCharDevice) + ); + return; + } + + spice_char_device_state_migrate_data_marshall(reds->agent_state.base, m); + spice_marshaller_add_uint8(m, reds->agent_state.client_agent_started); + + mig_data.agent2client.chunk_header = agent_state->vdi_chunk_header; + + /* agent to client partial msg */ + if (agent_state->read_state == VDI_PORT_READ_STATE_READ_HEADER) { + mig_data.agent2client.chunk_header_size = agent_state->recive_pos - + (uint8_t *)&agent_state->vdi_chunk_header; + + mig_data.agent2client.msg_header_done = FALSE; + mig_data.agent2client.msg_header_partial_len = 0; + spice_assert(!agent_state->read_filter.msg_data_to_read ); + } else { + mig_data.agent2client.chunk_header_size = sizeof(VDIChunkHeader); + mig_data.agent2client.chunk_header.size = agent_state->message_recive_len; + if (agent_state->read_state == VDI_PORT_READ_STATE_READ_DATA) { + /* in the middle of reading the message header (see reds_on_main_channel_migrate) */ + mig_data.agent2client.msg_header_done = FALSE; + mig_data.agent2client.msg_header_partial_len = + agent_state->recive_pos - agent_state->current_read_buf->data; + spice_assert(mig_data.agent2client.msg_header_partial_len < sizeof(VDAgentMessage)); + spice_assert(!agent_state->read_filter.msg_data_to_read); + } else { + mig_data.agent2client.msg_header_done = TRUE; + mig_data.agent2client.msg_remaining = agent_state->read_filter.msg_data_to_read; + mig_data.agent2client.msg_filter_result = agent_state->read_filter.result; + } + } + spice_marshaller_add_uint32(m, mig_data.agent2client.chunk_header_size); + spice_marshaller_add_ref(m, + (uint8_t *)&mig_data.agent2client.chunk_header, + sizeof(VDIChunkHeader)); + spice_marshaller_add_uint8(m, mig_data.agent2client.msg_header_done); + spice_marshaller_add_uint32(m, mig_data.agent2client.msg_header_partial_len); + m2 = spice_marshaller_get_ptr_submarshaller(m, 0); + spice_marshaller_add_ref(m2, agent_state->current_read_buf->data, + mig_data.agent2client.msg_header_partial_len); + spice_marshaller_add_uint32(m, mig_data.agent2client.msg_remaining); + spice_marshaller_add_uint8(m, mig_data.agent2client.msg_filter_result); + + mig_data.client2agent.msg_remaining = agent_state->write_filter.msg_data_to_read; + mig_data.client2agent.msg_filter_result = agent_state->write_filter.result; + spice_marshaller_add_uint32(m, mig_data.client2agent.msg_remaining); + spice_marshaller_add_uint8(m, mig_data.client2agent.msg_filter_result); + spice_debug("from agent filter: discard all %d, wait_msg %u, msg_filter_result %d", + agent_state->read_filter.discard_all, + agent_state->read_filter.msg_data_to_read, + agent_state->read_filter.result); + spice_debug("to agent filter: discard all %d, wait_msg %u, msg_filter_result %d", + agent_state->write_filter.discard_all, + agent_state->write_filter.msg_data_to_read, + agent_state->write_filter.result); } void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end) @@ -4130,6 +4198,7 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *s, const char* const char* cert_subject) { SpiceMigrateInterface *sif; + int try_seamless; spice_info(NULL); spice_assert(migration_interface); @@ -4149,9 +4218,20 @@ SPICE_GNUC_VISIBLE int spice_server_migrate_connect(SpiceServer *s, const char* reds->expect_migrate = TRUE; + /* + * seamless migration support was added to the client after the support in + * agent_connect_tokens, so there shouldn't be contradicition - if + * the client is capable of seamless migration, it is capbable of agent_connected_tokens. + * The demand for agent_connected_tokens support is in order to assure that if migration + * occured when the agent was not connected, the tokens state after migration will still + * be valid (see reds_reset_vdp for more details). + */ + try_seamless = reds->seamless_migration_enabled && + red_channel_test_remote_cap(&reds->main_channel->base, + SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS); /* main channel will take care of clients that are still during migration (at target)*/ if (main_channel_migrate_connect(reds->main_channel, reds->mig_spice, - reds->seamless_migration_enabled)) { + try_seamless)) { reds_mig_started(); } else { if (reds->num_clients == 0) { diff --git a/server/reds.h b/server/reds.h index a575d11c..e33e5182 100644 --- a/server/reds.h +++ b/server/reds.h @@ -135,7 +135,7 @@ void reds_client_disconnect(RedClient *client); // Temporary (?) for splitting main channel typedef struct MainMigrateData MainMigrateData; -void reds_marshall_migrate_data_item(SpiceMarshaller *m, MainMigrateData *data); +void reds_marshall_migrate_data(SpiceMarshaller *m); void reds_fill_channels(SpiceMsgChannels *channels_info); int reds_num_of_channels(void); int reds_num_of_clients(void); -- cgit