From: Christophe Fergeau <cfergeau@xxxxxxxxxx> This inherits from RedCharDevice. --- server/char-device.c | 3 +- server/reds-private.h | 2 +- server/reds.c | 527 ++++++++++++++++++++++++++++---------------------- 3 files changed, 304 insertions(+), 228 deletions(-) diff --git a/server/char-device.c b/server/char-device.c index a74626a..dcb0095 100644 --- a/server/char-device.c +++ b/server/char-device.c @@ -1240,7 +1240,8 @@ red_char_device_class_init(RedCharDeviceClass *klass) "RedsState instance", "RedsState instance", G_PARAM_STATIC_STRINGS | - G_PARAM_READWRITE)); + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); g_object_class_install_property(object_class, PROP_CLIENT_TOKENS_INTERVAL, g_param_spec_uint64("client-tokens-interval", diff --git a/server/reds-private.h b/server/reds-private.h index 8842aad..b3dac6d 100644 --- a/server/reds-private.h +++ b/server/reds-private.h @@ -88,7 +88,7 @@ typedef struct RedSSLParameters { char ciphersuite[256]; } RedSSLParameters; -typedef struct VDIPortState VDIPortState; +typedef struct RedCharDeviceVDIPort VDIPortState; struct RedsState { int listen_socket; diff --git a/server/reds.c b/server/reds.c index b563f4e..7be0f61 100644 --- a/server/reds.c +++ b/server/reds.c @@ -181,8 +181,8 @@ enum { VDI_PORT_READ_STATE_READ_DATA, }; -struct VDIPortState { - SpiceCharDeviceState *base; +struct RedCharDeviceVDIPortPrivate { + gboolean agent_attached; uint32_t plug_generation; int client_agent_started; @@ -216,6 +216,37 @@ typedef struct __attribute__ ((__packed__)) VDInternalBuf { u; } VDInternalBuf; +#define RED_TYPE_CHAR_DEVICE_VDIPORT red_char_device_vdi_port_get_type() + +#define RED_CHAR_DEVICE_VDIPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_CHAR_DEVICE_VDIPORT, RedCharDeviceVDIPort)) +#define RED_CHAR_DEVICE_VDIPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHAR_DEVICE_VDIPORT, RedCharDeviceVDIPortClass)) +#define RED_IS_CHAR_DEVICE_VDIPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_CHAR_DEVICE_VDIPORT)) +#define RED_IS_CHAR_DEVICE_VDIPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_CHAR_DEVICE_VDIPORT)) +#define RED_CHAR_DEVICE_VDIPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHAR_DEVICE_VDIPORT, RedCharDeviceVDIPortClass)) + +typedef struct RedCharDeviceVDIPort RedCharDeviceVDIPort; +typedef struct RedCharDeviceVDIPortClass RedCharDeviceVDIPortClass; +typedef struct RedCharDeviceVDIPortPrivate RedCharDeviceVDIPortPrivate; + +struct RedCharDeviceVDIPort +{ + RedCharDevice parent; + + RedCharDeviceVDIPortPrivate *priv; +}; + +struct RedCharDeviceVDIPortClass +{ + RedCharDeviceClass parent_class; +}; + +static GType red_char_device_vdi_port_get_type(void) G_GNUC_CONST; + +G_DEFINE_TYPE(RedCharDeviceVDIPort, red_char_device_vdi_port, RED_TYPE_CHAR_DEVICE) + +#define RED_CHAR_DEVICE_VDIPORT_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RED_TYPE_CHAR_DEVICE_VDIPORT, RedCharDeviceVDIPortPrivate)) + +static RedCharDeviceVDIPort *red_char_device_vdi_port_new(RedsState *reds); static void migrate_timeout(void *opaque); static RedsMigTargetClient* reds_mig_target_client_find(RedsState *reds, RedClient *client); @@ -450,16 +481,16 @@ static void reds_reset_vdp(RedsState *reds) VDIPortState *state = reds->agent_state; SpiceCharDeviceInterface *sif; - state->read_state = VDI_PORT_READ_STATE_READ_HEADER; - state->receive_pos = (uint8_t *)&state->vdi_chunk_header; - state->receive_len = sizeof(state->vdi_chunk_header); - state->message_receive_len = 0; - if (state->current_read_buf) { - vdi_port_read_buf_unref(state->current_read_buf); - state->current_read_buf = NULL; + state->priv->read_state = VDI_PORT_READ_STATE_READ_HEADER; + state->priv->receive_pos = (uint8_t *)&state->priv->vdi_chunk_header; + state->priv->receive_len = sizeof(state->priv->vdi_chunk_header); + state->priv->message_receive_len = 0; + if (state->priv->current_read_buf) { + vdi_port_read_buf_unref(state->priv->current_read_buf); + state->priv->current_read_buf = NULL; } /* Reset read filter to start with clean state when the agent reconnects */ - agent_msg_filter_init(&state->read_filter, reds->agent_copypaste, + agent_msg_filter_init(&state->priv->read_filter, reds->agent_copypaste, reds->agent_file_xfer, reds_use_client_monitors_config(reds), TRUE); /* Throw away pending chunks from the current (if any) and future @@ -468,9 +499,9 @@ static void reds_reset_vdp(RedsState *reds) * is disconnected. Currently, when an agent gets disconnected and reconnected, * messages that were directed to the previous instance of the agent continue * to be sent from the client. This TODO will require server, protocol, and client changes */ - state->write_filter.result = AGENT_MSG_FILTER_DISCARD; - state->write_filter.discard_all = TRUE; - state->client_agent_started = FALSE; + state->priv->write_filter.result = AGENT_MSG_FILTER_DISCARD; + state->priv->write_filter.discard_all = TRUE; + state->priv->client_agent_started = FALSE; /* resetting and not destroying the state as a workaround for a bad * tokens management in the vdagent protocol: @@ -485,10 +516,9 @@ static void reds_reset_vdp(RedsState *reds) */ if (red_channel_test_remote_cap(&reds->main_channel->base, SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) { - spice_char_device_state_destroy(state->base); - state->base = NULL; + state->priv->agent_attached = FALSE; } else { - spice_char_device_reset(state->base); + spice_char_device_reset(RED_CHAR_DEVICE(state)); } sif = spice_char_device_get_interface(reds->vdagent); @@ -536,11 +566,11 @@ void reds_client_disconnect(RedsState *reds, RedClient *client) reds_mig_remove_wait_disconnect_client(reds, client); } - if (reds->agent_state->base) { + if (reds->agent_state->priv->agent_attached) { /* note that vdagent might be NULL, if the vdagent was once * up and than was removed */ - if (spice_char_device_client_exists(reds->agent_state->base, client)) { - spice_char_device_client_remove(reds->agent_state->base, client); + if (spice_char_device_client_exists(RED_CHAR_DEVICE(reds->agent_state), client)) { + spice_char_device_client_remove(RED_CHAR_DEVICE(reds->agent_state), client); } } @@ -552,14 +582,14 @@ void reds_client_disconnect(RedsState *reds, RedClient *client) // if we are in the middle of one from another client) if (reds->num_clients == 0) { /* Let the agent know the client is disconnected */ - if (reds->agent_state->base) { + if (reds->agent_state->priv->agent_attached) { SpiceCharDeviceWriteBuffer *char_dev_buf; VDInternalBuf *internal_buf; uint32_t total_msg_size; total_msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage); char_dev_buf = spice_char_device_write_buffer_get_server_no_token( - reds->agent_state->base, total_msg_size); + RED_CHAR_DEVICE(reds->agent_state), total_msg_size); char_dev_buf->buf_used = total_msg_size; internal_buf = (VDInternalBuf *)char_dev_buf->buf; internal_buf->chunk_header.port = VDP_SERVER_PORT; @@ -569,21 +599,21 @@ void reds_client_disconnect(RedsState *reds, RedClient *client) internal_buf->header.opaque = 0; internal_buf->header.size = 0; - spice_char_device_write_buffer_add(reds->agent_state->base, + spice_char_device_write_buffer_add(RED_CHAR_DEVICE(reds->agent_state), char_dev_buf); } /* Reset write filter to start with clean state on client reconnect */ - agent_msg_filter_init(&reds->agent_state->write_filter, reds->agent_copypaste, + agent_msg_filter_init(&reds->agent_state->priv->write_filter, reds->agent_copypaste, reds->agent_file_xfer, reds_use_client_monitors_config(reds), TRUE); /* Throw away pending chunks from the current (if any) and future * messages read from the agent */ - reds->agent_state->read_filter.result = AGENT_MSG_FILTER_DISCARD; - reds->agent_state->read_filter.discard_all = TRUE; - free(reds->agent_state->mig_data); - reds->agent_state->mig_data = NULL; + reds->agent_state->priv->read_filter.result = AGENT_MSG_FILTER_DISCARD; + reds->agent_state->priv->read_filter.discard_all = TRUE; + free(reds->agent_state->priv->mig_data); + reds->agent_state->priv->mig_data = NULL; reds_mig_cleanup(reds); } @@ -693,9 +723,9 @@ static gboolean vdi_port_read_buf_process(VDIPortState *state, VDIReadBuf *buf, *error = FALSE; - switch (state->vdi_chunk_header.port) { + switch (state->priv->vdi_chunk_header.port) { case VDP_CLIENT_PORT: { - res = agent_msg_filter_process_data(&state->read_filter, + res = agent_msg_filter_process_data(&state->priv->read_filter, buf->data, buf->len); switch (res) { case AGENT_MSG_FILTER_OK: @@ -721,7 +751,7 @@ static VDIReadBuf *vdi_port_state_get_read_buf(VDIPortState *state) RingItem *item; VDIReadBuf *buf; - if (!(item = ring_get_head(&state->read_bufs))) { + if (!(item = ring_get_head(&state->priv->read_bufs))) { return NULL; } @@ -743,14 +773,14 @@ static VDIReadBuf* vdi_port_read_buf_ref(VDIReadBuf *buf) static void vdi_port_read_buf_unref(VDIReadBuf *buf) { if (!--buf->refs) { - ring_add(&buf->state->read_bufs, &buf->link); + ring_add(&buf->state->priv->read_bufs, &buf->link); /* read_one_msg_from_vdi_port may have never completed because the read_bufs ring was empty. So we call it again so it can complete its work if necessary. Note that since we can be called from spice_char_device_wakeup this can cause recursion, but we have protection for that */ - if (buf->state->base) { - spice_char_device_wakeup(buf->state->base); + if (buf->state->priv->agent_attached) { + spice_char_device_wakeup(RED_CHAR_DEVICE(buf->state)); } } } @@ -772,48 +802,48 @@ static SpiceCharDeviceMsgToClient *vdi_port_read_one_msg_from_device(SpiceCharDe spice_assert(reds->vdagent == sin); sif = spice_char_device_get_interface(reds->vdagent); while (reds->vdagent) { - switch (state->read_state) { + switch (state->priv->read_state) { case VDI_PORT_READ_STATE_READ_HEADER: - n = sif->read(reds->vdagent, state->receive_pos, state->receive_len); + n = sif->read(reds->vdagent, state->priv->receive_pos, state->priv->receive_len); if (!n) { return NULL; } - if ((state->receive_len -= n)) { - state->receive_pos += n; + if ((state->priv->receive_len -= n)) { + state->priv->receive_pos += n; return NULL; } - state->message_receive_len = state->vdi_chunk_header.size; - state->read_state = VDI_PORT_READ_STATE_GET_BUFF; + state->priv->message_receive_len = state->priv->vdi_chunk_header.size; + state->priv->read_state = VDI_PORT_READ_STATE_GET_BUFF; case VDI_PORT_READ_STATE_GET_BUFF: { - if (!(state->current_read_buf = vdi_port_state_get_read_buf(reds->agent_state))) { + if (!(state->priv->current_read_buf = vdi_port_state_get_read_buf(reds->agent_state))) { return NULL; } - state->receive_pos = state->current_read_buf->data; - state->receive_len = MIN(state->message_receive_len, - sizeof(state->current_read_buf->data)); - state->current_read_buf->len = state->receive_len; - state->message_receive_len -= state->receive_len; - state->read_state = VDI_PORT_READ_STATE_READ_DATA; + state->priv->receive_pos = state->priv->current_read_buf->data; + state->priv->receive_len = MIN(state->priv->message_receive_len, + sizeof(state->priv->current_read_buf->data)); + state->priv->current_read_buf->len = state->priv->receive_len; + state->priv->message_receive_len -= state->priv->receive_len; + state->priv->read_state = VDI_PORT_READ_STATE_READ_DATA; } case VDI_PORT_READ_STATE_READ_DATA: { gboolean error = FALSE; - n = sif->read(reds->vdagent, state->receive_pos, state->receive_len); + n = sif->read(reds->vdagent, state->priv->receive_pos, state->priv->receive_len); if (!n) { return NULL; } - if ((state->receive_len -= n)) { - state->receive_pos += n; + if ((state->priv->receive_len -= n)) { + state->priv->receive_pos += n; break; } - dispatch_buf = state->current_read_buf; - state->current_read_buf = NULL; - state->receive_pos = NULL; - if (state->message_receive_len == 0) { - state->read_state = VDI_PORT_READ_STATE_READ_HEADER; - state->receive_pos = (uint8_t *)&state->vdi_chunk_header; - state->receive_len = sizeof(state->vdi_chunk_header); + dispatch_buf = state->priv->current_read_buf; + state->priv->current_read_buf = NULL; + state->priv->receive_pos = NULL; + if (state->priv->message_receive_len == 0) { + state->priv->read_state = VDI_PORT_READ_STATE_READ_HEADER; + state->priv->receive_pos = (uint8_t *)&state->priv->vdi_chunk_header; + state->priv->receive_len = sizeof(state->priv->vdi_chunk_header); } else { - state->read_state = VDI_PORT_READ_STATE_GET_BUFF; + state->priv->read_state = VDI_PORT_READ_STATE_GET_BUFF; } if (vdi_port_read_buf_process(reds->agent_state, dispatch_buf, &error)) { return dispatch_buf; @@ -890,13 +920,13 @@ void reds_handle_agent_mouse_event(RedsState *reds, const VDAgentMouseState *mou VDInternalBuf *internal_buf; uint32_t total_msg_size; - if (!reds->inputs_channel || !reds->agent_state->base) { + if (!reds->inputs_channel || !reds->agent_state->priv->agent_attached) { return; } total_msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) + sizeof(VDAgentMouseState); - char_dev_buf = spice_char_device_write_buffer_get(reds->agent_state->base, + char_dev_buf = spice_char_device_write_buffer_get(RED_CHAR_DEVICE(reds->agent_state), NULL, total_msg_size); @@ -917,7 +947,7 @@ void reds_handle_agent_mouse_event(RedsState *reds, const VDAgentMouseState *mou internal_buf->u.mouse_state = *mouse_state; char_dev_buf->buf_used = total_msg_size; - spice_char_device_write_buffer_add(reds->agent_state->base, char_dev_buf); + spice_char_device_write_buffer_add(RED_CHAR_DEVICE(reds->agent_state), char_dev_buf); } int reds_get_n_channels(RedsState *reds) @@ -974,7 +1004,7 @@ void reds_fill_channels(RedsState *reds, SpiceMsgChannels *channels_info) void reds_on_main_agent_start(RedsState *reds, MainChannelClient *mcc, uint32_t num_tokens) { - SpiceCharDeviceState *dev_state = reds->agent_state->base; + SpiceCharDeviceState *dev_state = RED_CHAR_DEVICE(reds->agent_state); RedChannelClient *rcc; if (!reds->vdagent) { @@ -982,7 +1012,7 @@ void reds_on_main_agent_start(RedsState *reds, MainChannelClient *mcc, uint32_t } spice_assert(reds->vdagent->st && reds->vdagent->st == dev_state); rcc = main_channel_client_get_base(mcc); - reds->agent_state->client_agent_started = TRUE; + reds->agent_state->priv->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. @@ -1012,10 +1042,10 @@ void reds_on_main_agent_start(RedsState *reds, MainChannelClient *mcc, uint32_t num_tokens); } - agent_msg_filter_config(&reds->agent_state->write_filter, reds->agent_copypaste, + agent_msg_filter_config(&reds->agent_state->priv->write_filter, reds->agent_copypaste, reds->agent_file_xfer, reds_use_client_monitors_config(reds)); - reds->agent_state->write_filter.discard_all = FALSE; + reds->agent_state->priv->write_filter.discard_all = FALSE; } void reds_on_main_agent_tokens(RedsState *reds, MainChannelClient *mcc, uint32_t num_tokens) @@ -1034,7 +1064,7 @@ uint8_t *reds_get_agent_data_buffer(RedsState *reds, MainChannelClient *mcc, siz VDIPortState *dev_state = reds->agent_state; RedClient *client; - if (!dev_state->client_agent_started) { + if (!dev_state->priv->client_agent_started) { /* * agent got disconnected, and possibly got reconnected, but we still can receive * msgs that are addressed to the agent's old instance, in case they were @@ -1045,31 +1075,31 @@ uint8_t *reds_get_agent_data_buffer(RedsState *reds, MainChannelClient *mcc, siz return spice_malloc(size); } - spice_assert(dev_state->recv_from_client_buf == NULL); + spice_assert(dev_state->priv->recv_from_client_buf == NULL); client = main_channel_client_get_base(mcc)->client; - dev_state->recv_from_client_buf = spice_char_device_write_buffer_get(dev_state->base, - client, - size + sizeof(VDIChunkHeader)); - dev_state->recv_from_client_buf_pushed = FALSE; - return dev_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader); + dev_state->priv->recv_from_client_buf = spice_char_device_write_buffer_get(RED_CHAR_DEVICE(dev_state), + client, + size + sizeof(VDIChunkHeader)); + dev_state->priv->recv_from_client_buf_pushed = FALSE; + return dev_state->priv->recv_from_client_buf->buf + sizeof(VDIChunkHeader); } void reds_release_agent_data_buffer(RedsState *reds, uint8_t *buf) { VDIPortState *dev_state = reds->agent_state; - if (!dev_state->recv_from_client_buf) { + if (!dev_state->priv->recv_from_client_buf) { free(buf); return; } - spice_assert(buf == dev_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader)); - if (!dev_state->recv_from_client_buf_pushed) { - spice_char_device_write_buffer_release(reds->agent_state->base, - dev_state->recv_from_client_buf); + spice_assert(buf == dev_state->priv->recv_from_client_buf->buf + sizeof(VDIChunkHeader)); + if (!dev_state->priv->recv_from_client_buf_pushed) { + spice_char_device_write_buffer_release(RED_CHAR_DEVICE(reds->agent_state), + dev_state->priv->recv_from_client_buf); } - dev_state->recv_from_client_buf = NULL; - dev_state->recv_from_client_buf_pushed = FALSE; + dev_state->priv->recv_from_client_buf = NULL; + dev_state->priv->recv_from_client_buf_pushed = FALSE; } static void reds_client_monitors_config_cleanup(RedsState *reds) @@ -1113,7 +1143,7 @@ void reds_on_main_agent_data(RedsState *reds, MainChannelClient *mcc, void *mess VDIChunkHeader *header; int res; - res = agent_msg_filter_process_data(&reds->agent_state->write_filter, + res = agent_msg_filter_process_data(&reds->agent_state->priv->write_filter, message, size); switch (res) { case AGENT_MSG_FILTER_OK: @@ -1128,16 +1158,16 @@ void reds_on_main_agent_data(RedsState *reds, MainChannelClient *mcc, void *mess return; } - spice_assert(reds->agent_state->recv_from_client_buf); - spice_assert(message == reds->agent_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader)); + spice_assert(reds->agent_state->priv->recv_from_client_buf); + spice_assert(message == reds->agent_state->priv->recv_from_client_buf->buf + sizeof(VDIChunkHeader)); // TODO - start tracking agent data per channel - header = (VDIChunkHeader *)dev_state->recv_from_client_buf->buf; + header = (VDIChunkHeader *)dev_state->priv->recv_from_client_buf->buf; header->port = VDP_CLIENT_PORT; header->size = size; - dev_state->recv_from_client_buf->buf_used = sizeof(VDIChunkHeader) + size; + dev_state->priv->recv_from_client_buf->buf_used = sizeof(VDIChunkHeader) + size; - dev_state->recv_from_client_buf_pushed = TRUE; - spice_char_device_write_buffer_add(reds->agent_state->base, dev_state->recv_from_client_buf); + dev_state->priv->recv_from_client_buf_pushed = TRUE; + spice_char_device_write_buffer_add(RED_CHAR_DEVICE(reds->agent_state), dev_state->priv->recv_from_client_buf); } void reds_on_main_migrate_connected(RedsState *reds, int seamless) @@ -1177,20 +1207,20 @@ void reds_on_main_channel_migrate(RedsState *reds, MainChannelClient *mcc) spice_assert(reds->num_clients == 1); - if (agent_state->read_state != VDI_PORT_READ_STATE_READ_DATA) { + if (agent_state->priv->read_state != VDI_PORT_READ_STATE_READ_DATA) { return; } - spice_assert(agent_state->current_read_buf->data && - agent_state->receive_pos > agent_state->current_read_buf->data); - read_data_len = agent_state->receive_pos - agent_state->current_read_buf->data; + spice_assert(agent_state->priv->current_read_buf->data && + agent_state->priv->receive_pos > agent_state->priv->current_read_buf->data); + read_data_len = agent_state->priv->receive_pos - agent_state->priv->current_read_buf->data; - if (agent_state->read_filter.msg_data_to_read || + if (agent_state->priv->read_filter.msg_data_to_read || read_data_len > sizeof(VDAgentMessage)) { /* msg header has been read */ - VDIReadBuf *read_buf = agent_state->current_read_buf; + VDIReadBuf *read_buf = agent_state->priv->current_read_buf; gboolean error = FALSE; spice_debug("push partial read %u (msg first chunk? %d)", read_data_len, - !agent_state->read_filter.msg_data_to_read); + !agent_state->priv->read_filter.msg_data_to_read); read_buf->len = read_data_len; if (vdi_port_read_buf_process(reds->agent_state, read_buf, &error)) { @@ -1206,11 +1236,11 @@ void reds_on_main_channel_migrate(RedsState *reds, MainChannelClient *mcc) vdi_port_read_buf_unref(read_buf); } - spice_assert(agent_state->receive_len); - agent_state->message_receive_len += agent_state->receive_len; - agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF; - agent_state->current_read_buf = NULL; - agent_state->receive_pos = NULL; + spice_assert(agent_state->priv->receive_len); + agent_state->priv->message_receive_len += agent_state->priv->receive_len; + agent_state->priv->read_state = VDI_PORT_READ_STATE_GET_BUFF; + agent_state->priv->current_read_buf = NULL; + agent_state->priv->receive_pos = NULL; } } @@ -1227,11 +1257,12 @@ void reds_marshall_migrate_data(RedsState *reds, SpiceMarshaller *m) if (!reds->vdagent) { uint8_t *null_agent_mig_data; - 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) */ + /* MSG_AGENT_CONNECTED_TOKENS is supported by the client + (see spice_server_migrate_connect), so agent_attached + is set to FALSE when the agent is disconnected and + there is no need to track the client tokens + (see reds_reset_vdp) */ + spice_assert(!agent_state->priv->agent_attached); spice_char_device_state_migrate_data_marshall_empty(m); null_agent_mig_data = spice_marshaller_reserve_space(m, sizeof(SpiceMigrateDataMain) - @@ -1242,33 +1273,33 @@ void reds_marshall_migrate_data(RedsState *reds, SpiceMarshaller *m) return; } - spice_char_device_state_migrate_data_marshall(reds->agent_state->base, m); - spice_marshaller_add_uint8(m, reds->agent_state->client_agent_started); + spice_char_device_state_migrate_data_marshall(RED_CHAR_DEVICE(reds->agent_state), m); + spice_marshaller_add_uint8(m, reds->agent_state->priv->client_agent_started); - mig_data.agent2client.chunk_header = agent_state->vdi_chunk_header; + mig_data.agent2client.chunk_header = agent_state->priv->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->receive_pos - - (uint8_t *)&agent_state->vdi_chunk_header; + if (agent_state->priv->read_state == VDI_PORT_READ_STATE_READ_HEADER) { + mig_data.agent2client.chunk_header_size = agent_state->priv->receive_pos - + (uint8_t *)&agent_state->priv->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); + spice_assert(!agent_state->priv->read_filter.msg_data_to_read); } else { mig_data.agent2client.chunk_header_size = sizeof(VDIChunkHeader); - mig_data.agent2client.chunk_header.size = agent_state->message_receive_len; - if (agent_state->read_state == VDI_PORT_READ_STATE_READ_DATA) { + mig_data.agent2client.chunk_header.size = agent_state->priv->message_receive_len; + if (agent_state->priv->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->receive_pos - agent_state->current_read_buf->data; + agent_state->priv->receive_pos - agent_state->priv->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); + spice_assert(!agent_state->priv->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; + mig_data.agent2client.msg_remaining = agent_state->priv->read_filter.msg_data_to_read; + mig_data.agent2client.msg_filter_result = agent_state->priv->read_filter.result; } } spice_marshaller_add_uint32(m, mig_data.agent2client.chunk_header_size); @@ -1278,23 +1309,23 @@ void reds_marshall_migrate_data(RedsState *reds, SpiceMarshaller *m) 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(m2, agent_state->current_read_buf->data, + spice_marshaller_add(m2, agent_state->priv->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; + mig_data.client2agent.msg_remaining = agent_state->priv->write_filter.msg_data_to_read; + mig_data.client2agent.msg_filter_result = agent_state->priv->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); + agent_state->priv->read_filter.discard_all, + agent_state->priv->read_filter.msg_data_to_read, + agent_state->priv->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); + agent_state->priv->write_filter.discard_all, + agent_state->priv->write_filter.msg_data_to_read, + agent_state->priv->write_filter.result); } static int reds_agent_state_restore(RedsState *reds, SpiceMigrateDataMain *mig_data) @@ -1302,16 +1333,16 @@ static int reds_agent_state_restore(RedsState *reds, SpiceMigrateDataMain *mig_d VDIPortState *agent_state = reds->agent_state; uint32_t chunk_header_remaining; - agent_state->vdi_chunk_header = mig_data->agent2client.chunk_header; + agent_state->priv->vdi_chunk_header = mig_data->agent2client.chunk_header; spice_assert(mig_data->agent2client.chunk_header_size <= sizeof(VDIChunkHeader)); chunk_header_remaining = sizeof(VDIChunkHeader) - mig_data->agent2client.chunk_header_size; if (chunk_header_remaining) { - agent_state->read_state = VDI_PORT_READ_STATE_READ_HEADER; - agent_state->receive_pos = (uint8_t *)&agent_state->vdi_chunk_header + + agent_state->priv->read_state = VDI_PORT_READ_STATE_READ_HEADER; + agent_state->priv->receive_pos = (uint8_t *)&agent_state->priv->vdi_chunk_header + mig_data->agent2client.chunk_header_size; - agent_state->receive_len = chunk_header_remaining; + agent_state->priv->receive_len = chunk_header_remaining; } else { - agent_state->message_receive_len = agent_state->vdi_chunk_header.size; + agent_state->priv->message_receive_len = agent_state->priv->vdi_chunk_header.size; } if (!mig_data->agent2client.msg_header_done) { @@ -1320,49 +1351,49 @@ static int reds_agent_state_restore(RedsState *reds, SpiceMigrateDataMain *mig_d if (!chunk_header_remaining) { uint32_t cur_buf_size; - agent_state->read_state = VDI_PORT_READ_STATE_READ_DATA; - agent_state->current_read_buf = vdi_port_state_get_read_buf(reds->agent_state); - spice_assert(agent_state->current_read_buf); + agent_state->priv->read_state = VDI_PORT_READ_STATE_READ_DATA; + agent_state->priv->current_read_buf = vdi_port_state_get_read_buf(reds->agent_state); + spice_assert(agent_state->priv->current_read_buf); partial_msg_header = (uint8_t *)mig_data + mig_data->agent2client.msg_header_ptr - sizeof(SpiceMiniDataHeader); - memcpy(agent_state->current_read_buf->data, + memcpy(agent_state->priv->current_read_buf->data, partial_msg_header, mig_data->agent2client.msg_header_partial_len); - agent_state->receive_pos = agent_state->current_read_buf->data + + agent_state->priv->receive_pos = agent_state->priv->current_read_buf->data + mig_data->agent2client.msg_header_partial_len; - cur_buf_size = sizeof(agent_state->current_read_buf->data) - + cur_buf_size = sizeof(agent_state->priv->current_read_buf->data) - mig_data->agent2client.msg_header_partial_len; - agent_state->receive_len = MIN(agent_state->message_receive_len, cur_buf_size); - agent_state->current_read_buf->len = agent_state->receive_len + + agent_state->priv->receive_len = MIN(agent_state->priv->message_receive_len, cur_buf_size); + agent_state->priv->current_read_buf->len = agent_state->priv->receive_len + mig_data->agent2client.msg_header_partial_len; - agent_state->message_receive_len -= agent_state->receive_len; + agent_state->priv->message_receive_len -= agent_state->priv->receive_len; } else { spice_assert(mig_data->agent2client.msg_header_partial_len == 0); } } else { - agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF; - agent_state->current_read_buf = NULL; - agent_state->receive_pos = NULL; - agent_state->read_filter.msg_data_to_read = mig_data->agent2client.msg_remaining; - agent_state->read_filter.result = mig_data->agent2client.msg_filter_result; + agent_state->priv->read_state = VDI_PORT_READ_STATE_GET_BUFF; + agent_state->priv->current_read_buf = NULL; + agent_state->priv->receive_pos = NULL; + agent_state->priv->read_filter.msg_data_to_read = mig_data->agent2client.msg_remaining; + agent_state->priv->read_filter.result = mig_data->agent2client.msg_filter_result; } - agent_state->read_filter.discard_all = FALSE; - agent_state->write_filter.discard_all = !mig_data->client_agent_started; - agent_state->client_agent_started = mig_data->client_agent_started; + agent_state->priv->read_filter.discard_all = FALSE; + agent_state->priv->write_filter.discard_all = !mig_data->client_agent_started; + agent_state->priv->client_agent_started = mig_data->client_agent_started; - agent_state->write_filter.msg_data_to_read = mig_data->client2agent.msg_remaining; - agent_state->write_filter.result = mig_data->client2agent.msg_filter_result; + agent_state->priv->write_filter.msg_data_to_read = mig_data->client2agent.msg_remaining; + agent_state->priv->write_filter.result = mig_data->client2agent.msg_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); + agent_state->priv->write_filter.discard_all, + agent_state->priv->write_filter.msg_data_to_read, + agent_state->priv->write_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); - return spice_char_device_state_restore(agent_state->base, &mig_data->agent_base); + agent_state->priv->read_filter.discard_all, + agent_state->priv->read_filter.msg_data_to_read, + agent_state->priv->read_filter.result); + return spice_char_device_state_restore(RED_CHAR_DEVICE(agent_state), &mig_data->agent_base); } /* @@ -1385,13 +1416,13 @@ int reds_handle_migrate_data(RedsState *reds, MainChannelClient *mcc, reds_send_mm_time(reds); } if (mig_data->agent_base.connected) { - if (agent_state->base) { // agent was attached before migration data has arrived + if (agent_state->priv->agent_attached) { // agent was attached before migration data has arrived if (!reds->vdagent) { - spice_assert(agent_state->plug_generation > 0); + spice_assert(agent_state->priv->plug_generation > 0); main_channel_push_agent_disconnected(reds->main_channel); spice_debug("agent is no longer connected"); } else { - if (agent_state->plug_generation > 1) { + if (agent_state->priv->plug_generation > 1) { /* spice_char_device_state_reset takes care of not making the device wait for migration data */ spice_debug("agent has been detached and reattached before receiving migration data"); main_channel_push_agent_disconnected(reds->main_channel); @@ -1404,14 +1435,14 @@ int reds_handle_migrate_data(RedsState *reds, MainChannelClient *mcc, } else { /* restore agent starte when the agent gets attached */ spice_debug("saving mig_data"); - spice_assert(agent_state->plug_generation == 0); - agent_state->mig_data = spice_memdup(mig_data, size); + spice_assert(agent_state->priv->plug_generation == 0); + agent_state->priv->mig_data = spice_memdup(mig_data, size); } } else { spice_debug("agent was not attached on the source host"); if (reds->vdagent) { /* spice_char_device_client_remove disables waiting for migration data */ - spice_char_device_client_remove(agent_state->base, + spice_char_device_client_remove(RED_CHAR_DEVICE(agent_state), main_channel_client_get_base(mcc)->client); main_channel_push_agent_connected(reds->main_channel); } @@ -1746,12 +1777,12 @@ static void reds_handle_main_link(RedsState *reds, RedLinkInfo *link) if (mig_target) { spice_warning("unexpected: vdagent attached to destination during migration"); } - agent_msg_filter_config(&reds->agent_state->read_filter, + agent_msg_filter_config(&reds->agent_state->priv->read_filter, reds->agent_copypaste, reds->agent_file_xfer, reds_use_client_monitors_config(reds)); - reds->agent_state->read_filter.discard_all = FALSE; - reds->agent_state->plug_generation++; + reds->agent_state->priv->read_filter.discard_all = FALSE; + reds->agent_state->priv->plug_generation++; } if (!mig_target) { @@ -3024,25 +3055,12 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic { VDIPortState *state = reds->agent_state; SpiceCharDeviceInterface *sif; - SpiceCharDeviceCallbacks char_dev_state_cbs; - - if (!state->base) { - char_dev_state_cbs.read_one_msg_from_device = vdi_port_read_one_msg_from_device; - char_dev_state_cbs.ref_msg_to_client = vdi_port_ref_msg_to_client; - char_dev_state_cbs.unref_msg_to_client = vdi_port_unref_msg_to_client; - char_dev_state_cbs.send_msg_to_client = vdi_port_send_msg_to_client; - char_dev_state_cbs.send_tokens_to_client = vdi_port_send_tokens_to_client; - char_dev_state_cbs.remove_client = vdi_port_remove_client; - char_dev_state_cbs.on_free_self_token = vdi_port_on_free_self_token; - - state->base = spice_char_device_state_create(sin, - reds, - REDS_TOKENS_TO_SEND, - REDS_NUM_INTERNAL_AGENT_MESSAGES, - &char_dev_state_cbs, - reds); + + if (state->priv->agent_attached) { + spice_char_device_state_reset_dev_instance(RED_CHAR_DEVICE(state), sin); } else { - spice_char_device_state_reset_dev_instance(state->base, sin); + state->priv->agent_attached = TRUE; + g_object_set(G_OBJECT(state), "sin", sin, NULL); } reds->vdagent = sin; @@ -3054,13 +3072,13 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic } if (!reds_main_channel_connected(reds)) { - return state->base; + return RED_CHAR_DEVICE(state); } - state->read_filter.discard_all = FALSE; - reds->agent_state->plug_generation++; + state->priv->read_filter.discard_all = FALSE; + state->priv->plug_generation++; - if (reds->agent_state->mig_data || + if (state->priv->mig_data || red_channel_is_waiting_for_migrate_data(&reds->main_channel->base)) { /* Migration in progress (code is running on the destination host): * 1. Add the client to spice char device, if it was not already added. @@ -3069,10 +3087,10 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic * 2.b If this happens second ==> we already have spice migrate data * then restore state */ - if (!spice_char_device_client_exists(reds->agent_state->base, reds_get_client(reds))) { + if (!spice_char_device_client_exists(RED_CHAR_DEVICE(state), reds_get_client(reds))) { int client_added; - client_added = spice_char_device_client_add(reds->agent_state->base, + client_added = spice_char_device_client_add(RED_CHAR_DEVICE(state), reds_get_client(reds), TRUE, /* flow control */ REDS_VDI_PORT_NUM_RECEIVE_BUFFS, @@ -3086,12 +3104,12 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic } } - if (reds->agent_state->mig_data) { + if (state->priv->mig_data) { spice_debug("restoring state from stored migration data"); - spice_assert(reds->agent_state->plug_generation == 1); - reds_agent_state_restore(reds, reds->agent_state->mig_data); - free(reds->agent_state->mig_data); - reds->agent_state->mig_data = NULL; + spice_assert(state->priv->plug_generation == 1); + reds_agent_state_restore(reds, state->priv->mig_data); + free(state->priv->mig_data); + state->priv->mig_data = NULL; } else { spice_debug("waiting for migration data"); @@ -3102,7 +3120,7 @@ static SpiceCharDeviceState *attach_to_red_agent(RedsState *reds, SpiceCharDevic main_channel_push_agent_connected(reds->main_channel); } - return state->base; + return RED_CHAR_DEVICE(state); } SPICE_GNUC_VISIBLE void spice_server_char_device_wakeup(SpiceCharDeviceInstance* sin) @@ -3359,33 +3377,6 @@ SPICE_GNUC_VISIBLE int spice_server_remove_interface(SpiceBaseInstance *sin) return 0; } -static void reds_init_vd_agent_resources(RedsState *reds) -{ - VDIPortState *state; - int i; - - reds->agent_state = g_new0(VDIPortState, 1); - state = reds->agent_state; - ring_init(&state->read_bufs); - agent_msg_filter_init(&state->write_filter, reds->agent_copypaste, - reds->agent_file_xfer, - reds_use_client_monitors_config(reds), TRUE); - agent_msg_filter_init(&state->read_filter, reds->agent_copypaste, - reds->agent_file_xfer, - reds_use_client_monitors_config(reds), TRUE); - - state->read_state = VDI_PORT_READ_STATE_READ_HEADER; - state->receive_pos = (uint8_t *)&state->vdi_chunk_header; - state->receive_len = sizeof(state->vdi_chunk_header); - - for (i = 0; i < REDS_VDI_PORT_NUM_RECEIVE_BUFFS; i++) { - VDIReadBuf *buf = spice_new0(VDIReadBuf, 1); - buf->state = state; - ring_item_init(&buf->link); - ring_add(&reds->agent_state->read_bufs, &buf->link); - } -} - static int do_spice_init(RedsState *reds, SpiceCoreInterface *core_interface) { static gboolean first = TRUE; @@ -3399,7 +3390,7 @@ static int do_spice_init(RedsState *reds, SpiceCoreInterface *core_interface) reds->core = &core_interface_adapter; reds->listen_socket = -1; reds->secure_listen_socket = -1; - reds_init_vd_agent_resources(reds); + reds->agent_state = red_char_device_vdi_port_new(reds); ring_init(&reds->clients); reds->num_clients = 0; reds->main_dispatcher = main_dispatcher_new(reds, reds->core); @@ -3876,16 +3867,16 @@ SPICE_GNUC_VISIBLE int spice_server_set_agent_mouse(SpiceServer *reds, int enabl SPICE_GNUC_VISIBLE int spice_server_set_agent_copypaste(SpiceServer *reds, int enable) { reds->agent_copypaste = enable; - reds->agent_state->write_filter.copy_paste_enabled = reds->agent_copypaste; - reds->agent_state->read_filter.copy_paste_enabled = reds->agent_copypaste; + reds->agent_state->priv->write_filter.copy_paste_enabled = reds->agent_copypaste; + reds->agent_state->priv->read_filter.copy_paste_enabled = reds->agent_copypaste; return 0; } SPICE_GNUC_VISIBLE int spice_server_set_agent_file_xfer(SpiceServer *reds, int enable) { reds->agent_file_xfer = enable; - reds->agent_state->write_filter.file_xfer_enabled = reds->agent_file_xfer; - reds->agent_state->read_filter.file_xfer_enabled = reds->agent_file_xfer; + reds->agent_state->priv->write_filter.file_xfer_enabled = reds->agent_file_xfer; + reds->agent_state->priv->read_filter.file_xfer_enabled = reds->agent_file_xfer; return 0; } @@ -4292,3 +4283,87 @@ MainDispatcher* reds_get_main_dispatcher(RedsState *reds) { return reds->main_dispatcher; } + +static void red_char_device_vdi_port_constructed(GObject *object) +{ + RedCharDeviceVDIPort *dev = RED_CHAR_DEVICE_VDIPORT(object); + RedsState *reds; + + G_OBJECT_CLASS(red_char_device_vdi_port_parent_class)->constructed(object); + + g_object_get(dev, "spice-server", &reds, NULL); + + agent_msg_filter_init(&dev->priv->write_filter, reds->agent_copypaste, + reds->agent_file_xfer, + reds_use_client_monitors_config(reds), + TRUE); + agent_msg_filter_init(&dev->priv->read_filter, reds->agent_copypaste, + reds->agent_file_xfer, + reds_use_client_monitors_config(reds), + TRUE); +} + +static void +red_char_device_vdi_port_init(RedCharDeviceVDIPort *self) +{ + int i; + + self->priv = RED_CHAR_DEVICE_VDIPORT_PRIVATE(self); + + ring_init(&self->priv->read_bufs); + + self->priv->read_state = VDI_PORT_READ_STATE_READ_HEADER; + self->priv->receive_pos = (uint8_t *)&self->priv->vdi_chunk_header; + self->priv->receive_len = sizeof(self->priv->vdi_chunk_header); + + for (i = 0; i < REDS_VDI_PORT_NUM_RECEIVE_BUFFS; i++) { + VDIReadBuf *buf = spice_new0(VDIReadBuf, 1); + buf->state = self; + ring_item_init(&buf->link); + ring_add(&self->priv->read_bufs, &buf->link); + } +} + +static void +red_char_device_vdi_port_finalize(GObject *object) +{ + RedCharDeviceVDIPort *dev = RED_CHAR_DEVICE_VDIPORT(object); + + free(dev->priv->mig_data); + /* FIXME: need to free the VDIReadBuf allocated previously */ +} + +static void +red_char_device_vdi_port_class_init(RedCharDeviceVDIPortClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof (RedCharDeviceVDIPortPrivate)); + + object_class->finalize = red_char_device_vdi_port_finalize; + object_class->constructed = red_char_device_vdi_port_constructed; +} + +static RedCharDeviceVDIPort *red_char_device_vdi_port_new(RedsState *reds) +{ + RedCharDevice *char_dev; + SpiceCharDeviceCallbacks char_dev_cbs = { + .read_one_msg_from_device = vdi_port_read_one_msg_from_device, + .ref_msg_to_client = vdi_port_ref_msg_to_client, + .unref_msg_to_client = vdi_port_unref_msg_to_client, + .send_msg_to_client = vdi_port_send_msg_to_client, + .send_tokens_to_client = vdi_port_send_tokens_to_client, + .remove_client = vdi_port_remove_client, + .on_free_self_token = vdi_port_on_free_self_token, + }; + + char_dev = g_object_new(RED_TYPE_CHAR_DEVICE_VDIPORT, + "spice-server", reds, + "client-tokens-interval", REDS_TOKENS_TO_SEND, + "self-tokens", REDS_NUM_INTERNAL_AGENT_MESSAGES, + NULL); + + red_char_device_set_callbacks(RED_CHAR_DEVICE(char_dev), + &char_dev_cbs, reds); + return RED_CHAR_DEVICE_VDIPORT(char_dev); +} -- 2.5.5 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel