diff options
-rw-r--r-- | server/main_channel.c | 10 | ||||
-rw-r--r-- | server/red_channel.c | 2 | ||||
-rw-r--r-- | server/reds.c | 44 | ||||
-rw-r--r-- | server/reds.h | 1 |
4 files changed, 56 insertions, 1 deletions
diff --git a/server/main_channel.c b/server/main_channel.c index 648a06d3..6cdbc4dd 100644 --- a/server/main_channel.c +++ b/server/main_channel.c @@ -1160,10 +1160,17 @@ uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc) return mcc->bitrate_per_sec; } +static void main_channel_client_migrate(RedChannelClient *rcc) +{ + reds_on_main_channel_migrate(SPICE_CONTAINEROF(rcc, MainChannelClient, base)); + red_channel_client_default_migrate(rcc); +} + MainChannel* main_channel_init(void) { RedChannel *channel; ChannelCbs channel_cbs = { NULL, }; + ClientCbs client_cbs = {NULL, }; channel_cbs.config_socket = main_channel_config_socket; channel_cbs.on_disconnect = main_channel_client_on_disconnect; @@ -1187,6 +1194,9 @@ MainChannel* main_channel_init(void) spice_assert(channel); red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE); + client_cbs.migrate = main_channel_client_migrate; + red_channel_register_client_cbs(channel, &client_cbs); + return (MainChannel *)channel; } diff --git a/server/red_channel.c b/server/red_channel.c index 16335a32..803804e1 100644 --- a/server/red_channel.c +++ b/server/red_channel.c @@ -901,7 +901,7 @@ RedChannel *red_channel_create_parser(int size, void red_channel_register_client_cbs(RedChannel *channel, ClientCbs *client_cbs) { - spice_assert(client_cbs->connect); + spice_assert(client_cbs->connect || channel->type == SPICE_CHANNEL_MAIN); channel->client_cbs.connect = client_cbs->connect; if (client_cbs->disconnect) { diff --git a/server/reds.c b/server/reds.c index f1cc2f27..1deceb42 100644 --- a/server/reds.c +++ b/server/reds.c @@ -1219,6 +1219,50 @@ void reds_on_main_mouse_mode_request(void *message, size_t size) } } +/* + * Push partial agent data, even if not all the chunk was consumend, + * in order to avoid the roundtrip (src-server->client->dest-server) + */ +void reds_on_main_channel_migrate(MainChannelClient *mcc) +{ + VDIPortState *agent_state = &reds->agent_state; + uint32_t read_data_len; + + spice_assert(reds->num_clients == 1); + + if (agent_state->read_state != VDI_PORT_READ_STATE_READ_DATA) { + return; + } + spice_assert(agent_state->current_read_buf->data && + agent_state->recive_pos > agent_state->current_read_buf->data); + read_data_len = agent_state->recive_pos - agent_state->current_read_buf->data; + + if (agent_state->read_filter.msg_data_to_read || + read_data_len > sizeof(VDAgentMessage)) { /* msg header has been read */ + VDIReadBuf *read_buf = agent_state->current_read_buf; + + spice_debug("push partial read %u (msg first chunk? %d)", read_data_len, + !agent_state->read_filter.msg_data_to_read); + + read_buf->len = read_data_len; + if (vdi_port_read_buf_process(agent_state->vdi_chunk_header.port, read_buf)) { + main_channel_client_push_agent_data(mcc, + read_buf->data, + read_buf->len, + vdi_port_read_buf_release, + read_buf); + } else { + vdi_port_read_buf_unref(read_buf); + } + + spice_assert(agent_state->recive_len); + agent_state->message_recive_len += agent_state->recive_len; + agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF; + agent_state->current_read_buf = NULL; + agent_state->recive_pos = NULL; + } +} + #define MAIN_CHANNEL_MIG_DATA_VERSION 1 typedef struct WriteQueueInfo { diff --git a/server/reds.h b/server/reds.h index 779d0dbe..a575d11c 100644 --- a/server/reds.h +++ b/server/reds.h @@ -159,6 +159,7 @@ void reds_on_main_mouse_mode_request(void *message, size_t size); int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_version); void reds_on_client_semi_seamless_migrate_complete(RedClient *client); void reds_on_client_seamless_migrate_complete(RedClient *client); +void reds_on_main_channel_migrate(MainChannelClient *mcc); void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev); #endif |