847
679
buf->data, buf->len);
849
681
case AGENT_MSG_FILTER_OK:
851
683
case AGENT_MSG_FILTER_DISCARD:
852
ring_add(&state->read_bufs, &buf->link);
854
685
case AGENT_MSG_FILTER_PROTO_ERROR:
855
ring_add(&state->read_bufs, &buf->link);
856
686
reds_agent_remove();
859
main_channel_push_agent_data(reds->main_channel, buf->data, buf->len,
860
vdi_read_buf_release, buf);
863
690
case VDP_SERVER_PORT:
864
ring_add(&state->read_bufs, &buf->link);
867
ring_add(&state->read_bufs, &buf->link);
868
spice_printerr("invalid port");
693
spice_warning("invalid port");
869
694
reds_agent_remove();
873
/* Note this function MUST always be called in a while loop until it
874
returns 0. This is needed because it can cause new data available events
875
and its recursion protection causes those to get lost. Calling it until
876
it returns 0 ensures that all data has been consumed. */
877
static int read_from_vdi_port(void)
879
/* There are 2 scenarios where we can get called recursively:
880
1) spice-vmc vmc_read triggering flush of throttled data, recalling us
881
2) the buf we push to the client may be send immediately without
882
blocking, in which case its free function will recall us
883
This messes up the state machine, so ignore recursive calls.
884
This is why we always must be called in a loop. */
885
static int inside_call = 0;
699
static VDIReadBuf *vdi_port_read_buf_get(void)
701
VDIPortState *state = &reds->agent_state;
705
if (!(item = ring_get_head(&state->read_bufs))) {
710
buf = SPICE_CONTAINEROF(item, VDIReadBuf, link);
716
static VDIReadBuf* vdi_port_read_buf_ref(VDIReadBuf *buf)
722
static void vdi_port_read_buf_unref(VDIReadBuf *buf)
725
ring_add(&reds->agent_state.read_bufs, &buf->link);
727
/* read_one_msg_from_vdi_port may have never completed because the read_bufs
728
ring was empty. So we call it again so it can complete its work if
729
necessary. Note that since we can be called from spice_char_device_wakeup
730
this can cause recursion, but we have protection for that */
731
if (reds->agent_state.base) {
732
spice_char_device_wakeup(reds->agent_state.base);
737
/* reads from the device till completes reading a message that is addressed to the client,
738
* or otherwise, when reading from the device fails */
739
static SpiceCharDeviceMsgToClient *vdi_port_read_one_msg_from_device(SpiceCharDeviceInstance *sin,
887
742
VDIPortState *state = &reds->agent_state;
888
743
SpiceCharDeviceInterface *sif;
889
744
VDIReadBuf *dispatch_buf;
899
// discard data only if we are migrating (?) or vdagent has not been
750
spice_assert(vdagent == sin);
905
751
sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceCharDeviceInterface, base);
906
while (!quit_loop && vdagent) {
907
753
switch (state->read_state) {
908
case VDI_PORT_READ_STATE_READ_HADER:
754
case VDI_PORT_READ_STATE_READ_HEADER:
909
755
n = sif->read(vdagent, state->recive_pos, state->recive_len);
915
759
if ((state->recive_len -= n)) {
916
760
state->recive_pos += n;
920
763
state->message_recive_len = state->vdi_chunk_header.size;
921
764
state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
922
765
case VDI_PORT_READ_STATE_GET_BUFF: {
925
if (!(item = ring_get_head(&state->read_bufs))) {
766
if (!(state->current_read_buf = vdi_port_read_buf_get())) {
931
state->current_read_buf = (VDIReadBuf *)item;
932
769
state->recive_pos = state->current_read_buf->data;
933
770
state->recive_len = MIN(state->message_recive_len,
934
771
sizeof(state->current_read_buf->data));
1056
941
channels_info->num_of_channels = used_channels;
1057
942
if (used_channels != reds->num_of_channels) {
1058
spice_printerr("sent %d out of %d", used_channels, reds->num_of_channels);
943
spice_warning("sent %d out of %d", used_channels, reds->num_of_channels);
1062
void reds_on_main_agent_start(void)
947
void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens)
949
SpiceCharDeviceState *dev_state = reds->agent_state.base;
950
RedChannelClient *rcc;
955
spice_assert(vdagent->st && vdagent->st == dev_state);
956
rcc = main_channel_client_get_base(mcc);
957
reds->agent_state.client_agent_started = TRUE;
959
* Note that in older releases, send_tokens were set to ~0 on both client
960
* and server. The server ignored the client given tokens.
961
* Thanks to that, when an old client is connected to a new server,
962
* and vice versa, the sending from the server to the client won't have
963
* flow control, but will have no other problem.
965
if (!spice_char_device_client_exists(dev_state, rcc->client)) {
968
client_added = spice_char_device_client_add(dev_state,
970
TRUE, /* flow control */
971
REDS_VDI_PORT_NUM_RECEIVE_BUFFS,
972
REDS_AGENT_WINDOW_SIZE,
974
red_channel_client_waits_for_migrate_data(rcc));
977
spice_warning("failed to add client to agent");
978
reds_client_disconnect(rcc->client);
982
spice_char_device_send_to_client_tokens_set(dev_state,
1067
986
reds->agent_state.write_filter.discard_all = FALSE;
989
void reds_on_main_agent_tokens(MainChannelClient *mcc, uint32_t num_tokens)
994
spice_assert(vdagent->st);
995
spice_char_device_send_to_client_tokens_add(vdagent->st,
996
main_channel_client_get_base(mcc)->client,
1000
uint8_t *reds_get_agent_data_buffer(MainChannelClient *mcc, size_t size)
1002
VDIPortState *dev_state = &reds->agent_state;
1005
if (!dev_state->client_agent_started) {
1007
* agent got disconnected, and possibly got reconnected, but we still can receive
1008
* msgs that are addressed to the agent's old instance, in case they were
1009
* sent by the client before it received the AGENT_DISCONNECTED msg.
1010
* In such case, we will receive and discard the msgs (reds_reset_vdp takes care
1011
* of setting state->write_filter.result = AGENT_MSG_FILTER_DISCARD).
1013
return spice_malloc(size);
1016
spice_assert(dev_state->recv_from_client_buf == NULL);
1017
client = main_channel_client_get_base(mcc)->client;
1018
dev_state->recv_from_client_buf = spice_char_device_write_buffer_get(dev_state->base,
1020
size + sizeof(VDIChunkHeader));
1021
dev_state->recv_from_client_buf_pushed = FALSE;
1022
return dev_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader);
1025
void reds_release_agent_data_buffer(uint8_t *buf)
1027
VDIPortState *dev_state = &reds->agent_state;
1029
if (!dev_state->recv_from_client_buf) {
1034
spice_assert(buf == dev_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader));
1035
if (!dev_state->recv_from_client_buf_pushed) {
1036
spice_char_device_write_buffer_release(reds->agent_state.base,
1037
dev_state->recv_from_client_buf);
1039
dev_state->recv_from_client_buf = NULL;
1040
dev_state->recv_from_client_buf_pushed = FALSE;
1043
static void reds_client_monitors_config_cleanup(void)
1045
RedsClientMonitorsConfig *cmc = &reds->client_monitors_config;
1047
cmc->buffer_size = cmc->buffer_pos = 0;
1053
static void reds_on_main_agent_monitors_config(
1054
MainChannelClient *mcc, void *message, size_t size)
1056
VDAgentMessage *msg_header;
1057
VDAgentMonitorsConfig *monitors_config;
1058
RedsClientMonitorsConfig *cmc = &reds->client_monitors_config;
1060
cmc->buffer_size += size;
1061
cmc->buffer = realloc(cmc->buffer, cmc->buffer_size);
1062
spice_assert(cmc->buffer);
1064
memcpy(cmc->buffer + cmc->buffer_pos, message, size);
1065
cmc->buffer_pos += size;
1066
msg_header = (VDAgentMessage *)cmc->buffer;
1067
if (sizeof(VDAgentMessage) > cmc->buffer_size ||
1068
msg_header->size > cmc->buffer_size - sizeof(VDAgentMessage)) {
1069
spice_debug("not enough data yet. %d\n", cmc->buffer_size);
1072
monitors_config = (VDAgentMonitorsConfig *)(cmc->buffer + sizeof(*msg_header));
1073
spice_debug("%s: %d\n", __func__, monitors_config->num_of_monitors);
1074
red_dispatcher_client_monitors_config(monitors_config);
1075
reds_client_monitors_config_cleanup();
1070
1078
void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size)
1072
// TODO - use mcc (and start tracking agent data per channel. probably just move the whole
1073
// tokens accounting to mainchannel.
1074
RingItem *ring_item;
1080
VDIPortState *dev_state = &reds->agent_state;
1081
VDIChunkHeader *header;
1078
if (!reds->agent_state.num_client_tokens) {
1079
spice_printerr("token violation");
1083
--reds->agent_state.num_client_tokens;
1085
1084
res = agent_msg_filter_process_data(&reds->agent_state.write_filter,
1086
1085
message, size);
1088
1087
case AGENT_MSG_FILTER_OK:
1090
1089
case AGENT_MSG_FILTER_DISCARD:
1091
case AGENT_MSG_FILTER_MONITORS_CONFIG:
1092
reds_on_main_agent_monitors_config(mcc, message, size);
1093
1094
case AGENT_MSG_FILTER_PROTO_ERROR:
1094
1095
reds_disconnect();
1098
if (!(ring_item = ring_get_head(&reds->agent_state.external_bufs))) {
1099
spice_printerr("no agent free bufs");
1103
ring_remove(ring_item);
1104
buf = (VDAgentExtBuf *)ring_item;
1105
buf->base.now = (uint8_t *)&buf->base.chunk_header.port;
1106
buf->base.write_len = size + sizeof(VDIChunkHeader);
1107
buf->base.chunk_header.size = size;
1108
memcpy(buf->buf, message, size);
1109
ring_add(&reds->agent_state.write_queue, ring_item);
1110
write_to_vdi_port();
1099
spice_assert(reds->agent_state.recv_from_client_buf);
1100
spice_assert(message == reds->agent_state.recv_from_client_buf->buf + sizeof(VDIChunkHeader));
1101
// TODO - start tracking agent data per channel
1102
header = (VDIChunkHeader *)dev_state->recv_from_client_buf->buf;
1103
header->port = VDP_CLIENT_PORT;
1104
header->size = size;
1105
dev_state->recv_from_client_buf->buf_used = sizeof(VDIChunkHeader) + size;
1107
dev_state->recv_from_client_buf_pushed = TRUE;
1108
spice_char_device_write_buffer_add(reds->agent_state.base, dev_state->recv_from_client_buf);
1113
void reds_on_main_migrate_connected(void)
1111
void reds_on_main_migrate_connected(int seamless)
1113
reds->src_do_seamless_migrate = seamless;
1115
1114
if (reds->mig_wait_connect) {
1116
1115
reds_mig_cleanup();
1124
1123
if (reds->is_client_mouse_allowed) {
1125
1124
reds_set_mouse_mode(SPICE_MOUSE_MODE_CLIENT);
1127
spice_printerr("client mouse is disabled");
1126
spice_info("client mouse is disabled");
1130
1129
case SPICE_MOUSE_MODE_SERVER:
1131
1130
reds_set_mouse_mode(SPICE_MOUSE_MODE_SERVER);
1134
spice_printerr("unsupported mouse mode");
1138
#define MAIN_CHANNEL_MIG_DATA_VERSION 1
1140
typedef struct WriteQueueInfo {
1145
void reds_marshall_migrate_data_item(SpiceMarshaller *m, MainMigrateData *data)
1147
VDIPortState *state = &reds->agent_state;
1151
data->version = MAIN_CHANNEL_MIG_DATA_VERSION;
1153
data->agent_connected = !!vdagent;
1154
data->client_agent_started = !state->write_filter.discard_all;
1155
data->num_client_tokens = state->num_client_tokens;
1156
data->send_tokens = ~0;
1158
data->read_state = state->read_state;
1159
data->vdi_chunk_header = state->vdi_chunk_header;
1160
data->recive_len = state->recive_len;
1161
data->message_recive_len = state->message_recive_len;
1163
if (state->current_read_buf) {
1164
data->read_buf_len = state->current_read_buf->len;
1166
if (data->read_buf_len - data->recive_len) {
1167
spice_marshaller_add_ref(m,
1168
state->current_read_buf->data,
1169
data->read_buf_len - data->recive_len);
1172
data->read_buf_len = 0;
1175
now = &state->write_queue;
1176
data->write_queue_size = 0;
1177
while ((now = ring_prev(&state->write_queue, now))) {
1178
data->write_queue_size++;
1180
if (data->write_queue_size) {
1181
WriteQueueInfo *queue_info;
1183
queue_info = (WriteQueueInfo *)
1184
spice_marshaller_reserve_space(m,
1185
data->write_queue_size * sizeof(queue_info[0]));
1188
now = &state->write_queue;
1189
while ((now = ring_prev(&state->write_queue, now))) {
1190
VDIPortBuf *buf = (VDIPortBuf *)now;
1191
queue_info[buf_index].port = buf->chunk_header.port;
1192
queue_info[buf_index++].len = buf->write_len;
1193
spice_marshaller_add_ref(m, buf->now, buf->write_len);
1199
static int reds_main_channel_restore_vdi_read_state(MainMigrateData *data, uint8_t **in_pos,
1202
VDIPortState *state = &reds->agent_state;
1203
uint8_t *pos = *in_pos;
1204
RingItem *ring_item;
1206
state->read_state = data->read_state;
1207
state->vdi_chunk_header = data->vdi_chunk_header;
1208
state->recive_len = data->recive_len;
1209
state->message_recive_len = data->message_recive_len;
1211
switch (state->read_state) {
1212
case VDI_PORT_READ_STATE_READ_HADER:
1213
if (data->read_buf_len) {
1214
spice_printerr("unexpected receive buf");
1218
state->recive_pos = (uint8_t *)(&state->vdi_chunk_header + 1) - state->recive_len;
1220
case VDI_PORT_READ_STATE_GET_BUFF:
1221
if (state->message_recive_len > state->vdi_chunk_header.size) {
1222
spice_printerr("invalid message receive len");
1227
if (data->read_buf_len) {
1228
spice_printerr("unexpected receive buf");
1233
case VDI_PORT_READ_STATE_READ_DATA: {
1237
if (!data->read_buf_len) {
1238
spice_printerr("read state and read_buf_len == 0");
1243
if (state->message_recive_len > state->vdi_chunk_header.size) {
1244
spice_printerr("invalid message receive len");
1250
if (!(ring_item = ring_get_head(&state->read_bufs))) {
1251
spice_printerr("get read buf failed");
1256
ring_remove(ring_item);
1257
buff = state->current_read_buf = (VDIReadBuf *)ring_item;
1258
buff->len = data->read_buf_len;
1259
n = buff->len - state->recive_len;
1260
if (buff->len > SPICE_AGENT_MAX_DATA_SIZE || n > SPICE_AGENT_MAX_DATA_SIZE) {
1261
spice_printerr("bad read position");
1265
memcpy(buff->data, pos, n);
1267
state->recive_pos = buff->data + n;
1271
spice_printerr("invalid read state");
1279
static void free_tmp_internal_buf(VDIPortBuf *buf)
1284
static int reds_main_channel_restore_vdi_wqueue(MainMigrateData *data, uint8_t *pos, uint8_t *end)
1286
VDIPortState *state = &reds->agent_state;
1287
WriteQueueInfo *inf;
1288
WriteQueueInfo *inf_end;
1289
RingItem *ring_item;
1291
if (!data->write_queue_size) {
1295
inf = (WriteQueueInfo *)pos;
1296
inf_end = inf + data->write_queue_size;
1297
pos = (uint8_t *)inf_end;
1299
spice_printerr("access violation");
1304
for (; inf < inf_end; inf++) {
1305
if (pos + inf->len > end) {
1306
spice_printerr("access violation");
1310
if (inf->port == VDP_SERVER_PORT) {
1313
if (inf->len > sizeof(*buf) - SPICE_OFFSETOF(VDInternalBuf, header)) {
1314
spice_printerr("bad buffer len");
1318
buf = spice_new(VDInternalBuf, 1);
1319
ring_item_init(&buf->base.link);
1320
buf->base.free = free_tmp_internal_buf;
1321
buf->base.now = (uint8_t *)&buf->base.chunk_header;
1322
buf->base.write_len = inf->len;
1323
memcpy(buf->base.now, pos, buf->base.write_len);
1324
ring_add(&reds->agent_state.write_queue, &buf->base.link);
1325
} else if (inf->port == VDP_CLIENT_PORT) {
1328
state->num_tokens--;
1329
if (inf->len > sizeof(*buf) - SPICE_OFFSETOF(VDAgentExtBuf, buf)) {
1330
spice_printerr("bad buffer len");
1334
if (!(ring_item = ring_get_head(&reds->agent_state.external_bufs))) {
1335
spice_printerr("no external buff");
1339
ring_remove(ring_item);
1340
buf = (VDAgentExtBuf *)ring_item;
1341
memcpy(&buf->buf, pos, inf->len);
1342
buf->base.now = (uint8_t *)buf->buf;
1343
buf->base.write_len = inf->len;
1344
ring_add(&reds->agent_state.write_queue, &buf->base.link);
1346
spice_printerr("invalid data");
1355
void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end)
1357
VDIPortState *state = &reds->agent_state;
1360
if (data->version != MAIN_CHANNEL_MIG_DATA_VERSION) {
1361
spice_printerr("version mismatch");
1366
state->num_client_tokens = data->num_client_tokens;
1367
spice_assert(state->num_client_tokens + data->write_queue_size <= REDS_AGENT_WINDOW_SIZE +
1368
REDS_NUM_INTERNAL_AGENT_MESSAGES);
1369
state->num_tokens = REDS_AGENT_WINDOW_SIZE - state->num_client_tokens;
1371
if (!data->agent_connected) {
1133
spice_warning("unsupported mouse mode");
1138
* Push partial agent data, even if not all the chunk was consumend,
1139
* in order to avoid the roundtrip (src-server->client->dest-server)
1141
void reds_on_main_channel_migrate(MainChannelClient *mcc)
1143
VDIPortState *agent_state = &reds->agent_state;
1144
uint32_t read_data_len;
1146
spice_assert(reds->num_clients == 1);
1148
if (agent_state->read_state != VDI_PORT_READ_STATE_READ_DATA) {
1151
spice_assert(agent_state->current_read_buf->data &&
1152
agent_state->recive_pos > agent_state->current_read_buf->data);
1153
read_data_len = agent_state->recive_pos - agent_state->current_read_buf->data;
1155
if (agent_state->read_filter.msg_data_to_read ||
1156
read_data_len > sizeof(VDAgentMessage)) { /* msg header has been read */
1157
VDIReadBuf *read_buf = agent_state->current_read_buf;
1159
spice_debug("push partial read %u (msg first chunk? %d)", read_data_len,
1160
!agent_state->read_filter.msg_data_to_read);
1162
read_buf->len = read_data_len;
1163
if (vdi_port_read_buf_process(agent_state->vdi_chunk_header.port, read_buf)) {
1164
main_channel_client_push_agent_data(mcc,
1167
vdi_port_read_buf_release,
1170
vdi_port_read_buf_unref(read_buf);
1173
spice_assert(agent_state->recive_len);
1174
agent_state->message_recive_len += agent_state->recive_len;
1175
agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
1176
agent_state->current_read_buf = NULL;
1177
agent_state->recive_pos = NULL;
1181
void reds_marshall_migrate_data(SpiceMarshaller *m)
1183
SpiceMigrateDataMain mig_data;
1184
VDIPortState *agent_state = &reds->agent_state;
1185
SpiceMarshaller *m2;
1187
memset(&mig_data, 0, sizeof(mig_data));
1188
spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_MAIN_MAGIC);
1189
spice_marshaller_add_uint32(m, SPICE_MIGRATE_DATA_MAIN_VERSION);
1192
uint8_t *null_agent_mig_data;
1194
spice_assert(!agent_state->base); /* MSG_AGENT_CONNECTED_TOKENS is supported by the client
1195
(see spice_server_migrate_connect), so SpiceCharDeviceState
1196
is destroyed when the agent is disconnected and
1197
there is no need to track the client tokens
1198
(see reds_reset_vdp) */
1199
spice_char_device_state_migrate_data_marshall_empty(m);
1200
null_agent_mig_data = spice_marshaller_reserve_space(m,
1201
sizeof(SpiceMigrateDataMain) -
1202
sizeof(SpiceMigrateDataCharDevice));
1203
memset(null_agent_mig_data,
1205
sizeof(SpiceMigrateDataMain) - sizeof(SpiceMigrateDataCharDevice));
1209
spice_char_device_state_migrate_data_marshall(reds->agent_state.base, m);
1210
spice_marshaller_add_uint8(m, reds->agent_state.client_agent_started);
1212
mig_data.agent2client.chunk_header = agent_state->vdi_chunk_header;
1214
/* agent to client partial msg */
1215
if (agent_state->read_state == VDI_PORT_READ_STATE_READ_HEADER) {
1216
mig_data.agent2client.chunk_header_size = agent_state->recive_pos -
1217
(uint8_t *)&agent_state->vdi_chunk_header;
1219
mig_data.agent2client.msg_header_done = FALSE;
1220
mig_data.agent2client.msg_header_partial_len = 0;
1221
spice_assert(!agent_state->read_filter.msg_data_to_read);
1223
mig_data.agent2client.chunk_header_size = sizeof(VDIChunkHeader);
1224
mig_data.agent2client.chunk_header.size = agent_state->message_recive_len;
1225
if (agent_state->read_state == VDI_PORT_READ_STATE_READ_DATA) {
1226
/* in the middle of reading the message header (see reds_on_main_channel_migrate) */
1227
mig_data.agent2client.msg_header_done = FALSE;
1228
mig_data.agent2client.msg_header_partial_len =
1229
agent_state->recive_pos - agent_state->current_read_buf->data;
1230
spice_assert(mig_data.agent2client.msg_header_partial_len < sizeof(VDAgentMessage));
1231
spice_assert(!agent_state->read_filter.msg_data_to_read);
1233
mig_data.agent2client.msg_header_done = TRUE;
1234
mig_data.agent2client.msg_remaining = agent_state->read_filter.msg_data_to_read;
1235
mig_data.agent2client.msg_filter_result = agent_state->read_filter.result;
1238
spice_marshaller_add_uint32(m, mig_data.agent2client.chunk_header_size);
1239
spice_marshaller_add(m,
1240
(uint8_t *)&mig_data.agent2client.chunk_header,
1241
sizeof(VDIChunkHeader));
1242
spice_marshaller_add_uint8(m, mig_data.agent2client.msg_header_done);
1243
spice_marshaller_add_uint32(m, mig_data.agent2client.msg_header_partial_len);
1244
m2 = spice_marshaller_get_ptr_submarshaller(m, 0);
1245
spice_marshaller_add(m2, agent_state->current_read_buf->data,
1246
mig_data.agent2client.msg_header_partial_len);
1247
spice_marshaller_add_uint32(m, mig_data.agent2client.msg_remaining);
1248
spice_marshaller_add_uint8(m, mig_data.agent2client.msg_filter_result);
1250
mig_data.client2agent.msg_remaining = agent_state->write_filter.msg_data_to_read;
1251
mig_data.client2agent.msg_filter_result = agent_state->write_filter.result;
1252
spice_marshaller_add_uint32(m, mig_data.client2agent.msg_remaining);
1253
spice_marshaller_add_uint8(m, mig_data.client2agent.msg_filter_result);
1254
spice_debug("from agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
1255
agent_state->read_filter.discard_all,
1256
agent_state->read_filter.msg_data_to_read,
1257
agent_state->read_filter.result);
1258
spice_debug("to agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
1259
agent_state->write_filter.discard_all,
1260
agent_state->write_filter.msg_data_to_read,
1261
agent_state->write_filter.result);
1264
static int reds_agent_state_restore(SpiceMigrateDataMain *mig_data)
1266
VDIPortState *agent_state = &reds->agent_state;
1267
uint32_t chunk_header_remaining;
1269
agent_state->vdi_chunk_header = mig_data->agent2client.chunk_header;
1270
spice_assert(mig_data->agent2client.chunk_header_size <= sizeof(VDIChunkHeader));
1271
chunk_header_remaining = sizeof(VDIChunkHeader) - mig_data->agent2client.chunk_header_size;
1272
if (chunk_header_remaining) {
1273
agent_state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
1274
agent_state->recive_pos = (uint8_t *)&agent_state->vdi_chunk_header +
1275
mig_data->agent2client.chunk_header_size;
1276
agent_state->recive_len = chunk_header_remaining;
1278
agent_state->message_recive_len = agent_state->vdi_chunk_header.size;
1281
if (!mig_data->agent2client.msg_header_done) {
1282
uint8_t *partial_msg_header;
1284
if (!chunk_header_remaining) {
1285
uint32_t cur_buf_size;
1287
agent_state->read_state = VDI_PORT_READ_STATE_READ_DATA;
1288
agent_state->current_read_buf = vdi_port_read_buf_get();
1289
spice_assert(agent_state->current_read_buf);
1290
partial_msg_header = (uint8_t *)mig_data + mig_data->agent2client.msg_header_ptr -
1291
sizeof(SpiceMiniDataHeader);
1292
memcpy(agent_state->current_read_buf->data,
1294
mig_data->agent2client.msg_header_partial_len);
1295
agent_state->recive_pos = agent_state->current_read_buf->data +
1296
mig_data->agent2client.msg_header_partial_len;
1297
cur_buf_size = sizeof(agent_state->current_read_buf->data) -
1298
mig_data->agent2client.msg_header_partial_len;
1299
agent_state->recive_len = MIN(agent_state->message_recive_len, cur_buf_size);
1300
agent_state->current_read_buf->len = agent_state->recive_len +
1301
mig_data->agent2client.msg_header_partial_len;
1302
agent_state->message_recive_len -= agent_state->recive_len;
1304
spice_assert(mig_data->agent2client.msg_header_partial_len == 0);
1307
agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
1308
agent_state->current_read_buf = NULL;
1309
agent_state->recive_pos = NULL;
1310
agent_state->read_filter.msg_data_to_read = mig_data->agent2client.msg_remaining;
1311
agent_state->read_filter.result = mig_data->agent2client.msg_filter_result;
1314
agent_state->read_filter.discard_all = FALSE;
1315
agent_state->write_filter.discard_all = !mig_data->client_agent_started;
1316
agent_state->client_agent_started = mig_data->client_agent_started;
1318
agent_state->write_filter.msg_data_to_read = mig_data->client2agent.msg_remaining;
1319
agent_state->write_filter.result = mig_data->client2agent.msg_filter_result;
1321
spice_debug("to agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
1322
agent_state->write_filter.discard_all,
1323
agent_state->write_filter.msg_data_to_read,
1324
agent_state->write_filter.result);
1325
spice_debug("from agent filter: discard all %d, wait_msg %u, msg_filter_result %d",
1326
agent_state->read_filter.discard_all,
1327
agent_state->read_filter.msg_data_to_read,
1328
agent_state->read_filter.result);
1329
return spice_char_device_state_restore(agent_state->base, &mig_data->agent_base);
1333
* The agent device is not attached to the dest before migration is completed. It is
1334
* attached only after the vm is started. It might be attached before or after
1335
* the migration data has reached the server.
1337
int reds_handle_migrate_data(MainChannelClient *mcc, SpiceMigrateDataMain *mig_data, uint32_t size)
1339
VDIPortState *agent_state = &reds->agent_state;
1341
if (mig_data->agent_base.connected) {
1342
if (agent_state->base) { // agent was attached before migration data has arrived
1344
spice_assert(agent_state->plug_generation > 0);
1345
main_channel_push_agent_disconnected(reds->main_channel);
1346
spice_debug("agent is no longer connected");
1348
if (agent_state->plug_generation > 1) {
1349
/* spice_char_device_state_reset takes care of not making the device wait for migration data */
1350
spice_debug("agent has been detached and reattached before receiving migration data");
1351
main_channel_push_agent_disconnected(reds->main_channel);
1352
main_channel_push_agent_connected(reds->main_channel);
1354
return reds_agent_state_restore(mig_data);
1358
/* restore agent starte when the agent gets attached */
1359
spice_assert(agent_state->plug_generation == 0);
1360
agent_state->mig_data = spice_memdup(mig_data, size);
1364
/* spice_char_device_client_remove disables waiting for migration data */
1365
spice_char_device_client_remove(agent_state->base,
1366
main_channel_client_get_base(mcc)->client);
1373
1367
main_channel_push_agent_connected(reds->main_channel);
1379
main_channel_push_agent_disconnected(reds->main_channel);
1383
if (state->plug_generation > 1) {
1384
main_channel_push_agent_disconnected(reds->main_channel);
1385
main_channel_push_agent_connected(reds->main_channel);
1389
state->write_filter.discard_all = !data->client_agent_started;
1391
pos = (uint8_t *)(data + 1);
1393
if (!reds_main_channel_restore_vdi_read_state(data, &pos, end)) {
1397
reds_main_channel_restore_vdi_wqueue(data, pos, end);
1398
spice_assert(state->num_client_tokens + state->num_tokens == REDS_AGENT_WINDOW_SIZE);
1400
while (write_to_vdi_port() || read_from_vdi_port());
1403
1374
static int sync_write(RedsStream *stream, const void *in_buf, size_t n)
3553
3790
const SpiceBaseInterface *interface = sin->sif;
3555
3792
if (strcmp(interface->type, SPICE_INTERFACE_TABLET) == 0) {
3556
spice_printerr("remove SPICE_INTERFACE_TABLET");
3793
spice_info("remove SPICE_INTERFACE_TABLET");
3557
3794
inputs_detach_tablet(SPICE_CONTAINEROF(sin, SpiceTabletInstance, base));
3558
3795
reds_update_mouse_mode();
3559
3796
} else if (strcmp(interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
3560
spice_printerr("remove SPICE_INTERFACE_PLAYBACK");
3797
spice_info("remove SPICE_INTERFACE_PLAYBACK");
3561
3798
snd_detach_playback(SPICE_CONTAINEROF(sin, SpicePlaybackInstance, base));
3563
3799
} else if (strcmp(interface->type, SPICE_INTERFACE_RECORD) == 0) {
3564
spice_printerr("remove SPICE_INTERFACE_RECORD");
3800
spice_info("remove SPICE_INTERFACE_RECORD");
3565
3801
snd_detach_record(SPICE_CONTAINEROF(sin, SpiceRecordInstance, base));
3567
3802
} else if (strcmp(interface->type, SPICE_INTERFACE_CHAR_DEVICE) == 0) {
3568
3803
spice_server_char_device_remove_interface(sin);
3570
spice_error("VD_INTERFACE_REMOVING unsupported");
3805
spice_warning("VD_INTERFACE_REMOVING unsupported");
3577
static void free_external_agent_buff(VDIPortBuf *in_buf)
3579
VDIPortState *state = &reds->agent_state;
3581
ring_add(&state->external_bufs, &in_buf->link);
3585
static void free_internal_agent_buff(VDIPortBuf *in_buf)
3587
VDIPortState *state = &reds->agent_state;
3589
ring_add(&state->internal_bufs, &in_buf->link);
3590
if (inputs_inited() && reds->pending_mouse_event) {
3591
reds_handle_agent_mouse_event(inputs_get_mouse_state());
3595
3812
static void init_vd_agent_resources(void)
3597
3814
VDIPortState *state = &reds->agent_state;
3600
ring_init(&state->external_bufs);
3601
ring_init(&state->internal_bufs);
3602
ring_init(&state->write_queue);
3603
3817
ring_init(&state->read_bufs);
3604
3818
agent_msg_filter_init(&state->write_filter, agent_copypaste, TRUE);
3605
3819
agent_msg_filter_init(&state->read_filter, agent_copypaste, TRUE);
3607
state->read_state = VDI_PORT_READ_STATE_READ_HADER;
3821
state->read_state = VDI_PORT_READ_STATE_READ_HEADER;
3608
3822
state->recive_pos = (uint8_t *)&state->vdi_chunk_header;
3609
3823
state->recive_len = sizeof(state->vdi_chunk_header);
3611
for (i = 0; i < REDS_AGENT_WINDOW_SIZE; i++) {
3612
VDAgentExtBuf *buf = spice_new0(VDAgentExtBuf, 1);
3613
ring_item_init(&buf->base.link);
3614
buf->base.chunk_header.port = VDP_CLIENT_PORT;
3615
buf->base.free = free_external_agent_buff;
3616
ring_add(&reds->agent_state.external_bufs, &buf->base.link);
3619
for (i = 0; i < REDS_NUM_INTERNAL_AGENT_MESSAGES; i++) {
3620
VDInternalBuf *buf = spice_new0(VDInternalBuf, 1);
3621
ring_item_init(&buf->base.link);
3622
buf->base.free = free_internal_agent_buff;
3623
buf->base.chunk_header.port = VDP_SERVER_PORT;
3624
buf->base.chunk_header.size = sizeof(VDAgentMessage) + sizeof(VDAgentMouseState);
3625
buf->header.protocol = VD_AGENT_PROTOCOL;
3626
buf->header.type = VD_AGENT_MOUSE_STATE;
3627
buf->header.opaque = 0;
3628
buf->header.size = sizeof(VDAgentMouseState);
3629
ring_add(&reds->agent_state.internal_bufs, &buf->base.link);
3632
3825
for (i = 0; i < REDS_VDI_PORT_NUM_RECEIVE_BUFFS; i++) {
3633
3826
VDIReadBuf *buf = spice_new0(VDIReadBuf, 1);
3634
3827
ring_item_init(&buf->link);