summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/main_channel.c10
-rw-r--r--server/red_channel.c2
-rw-r--r--server/reds.c44
-rw-r--r--server/reds.h1
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