> > 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", This part should be moved to SpiceCharDeviceState patch. > 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); > +} I'll split the priv changes Frediano _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel