diff options
Diffstat (limited to 'server/red-channel.c')
-rw-r--r-- | server/red-channel.c | 645 |
1 files changed, 436 insertions, 209 deletions
diff --git a/server/red-channel.c b/server/red-channel.c index af49824d..6269a808 100644 --- a/server/red-channel.c +++ b/server/red-channel.c @@ -69,9 +69,135 @@ * from the channel's thread. */ -void red_channel_receive(RedChannel *channel) +G_DEFINE_ABSTRACT_TYPE(RedChannel, red_channel, G_TYPE_OBJECT) + +#define CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), RED_TYPE_CHANNEL, RedChannelPrivate)) + +struct RedChannelPrivate +{ + uint32_t type; + uint32_t id; + + SpiceCoreInterfaceInternal *core; + gboolean handle_acks; + + // RedChannel will hold only connected channel clients (logic - when pushing pipe item to all channel clients, there + // is no need to go over disconnect clients) + // . While client will hold the channel clients till it is destroyed + // and then it will destroy them as well. + // However RCC still holds a reference to the Channel. + // Maybe replace these logic with ref count? + // TODO: rename to 'connected_clients'? + GList *clients; + + RedChannelCapabilities local_caps; + uint32_t migration_flags; + + void *data; + + OutgoingHandlerInterface outgoing_cb; + IncomingHandlerInterface incoming_cb; + + ClientCbs client_cbs; + // TODO: when different channel_clients are in different threads from Channel -> need to protect! + pthread_t thread_id; + RedsState *reds; +#ifdef RED_STATISTICS + StatNodeRef stat; + uint64_t *out_bytes_counter; +#endif +}; + +enum { + PROP0, + PROP_SPICE_SERVER, + PROP_CORE_INTERFACE, + PROP_TYPE, + PROP_ID, + PROP_HANDLE_ACKS, + PROP_MIGRATION_FLAGS +}; + +static void +red_channel_get_property(GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + RedChannel *self = RED_CHANNEL(object); + + switch (property_id) + { + case PROP_SPICE_SERVER: + g_value_set_pointer(value, self->priv->reds); + break; + case PROP_CORE_INTERFACE: + g_value_set_pointer(value, self->priv->core); + break; + case PROP_TYPE: + g_value_set_int(value, self->priv->type); + break; + case PROP_ID: + g_value_set_uint(value, self->priv->id); + break; + case PROP_HANDLE_ACKS: + g_value_set_boolean(value, self->priv->handle_acks); + break; + case PROP_MIGRATION_FLAGS: + g_value_set_uint(value, self->priv->migration_flags); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void +red_channel_set_property(GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) { - g_list_foreach(channel->clients, (GFunc)red_channel_client_receive, NULL); + RedChannel *self = RED_CHANNEL(object); + + switch (property_id) + { + case PROP_SPICE_SERVER: + self->priv->reds = g_value_get_pointer(value); + break; + case PROP_CORE_INTERFACE: + self->priv->core = g_value_get_pointer(value); + break; + case PROP_TYPE: + self->priv->type = g_value_get_int(value); + break; + case PROP_ID: + self->priv->id = g_value_get_uint(value); + break; + case PROP_HANDLE_ACKS: + self->priv->handle_acks = g_value_get_boolean(value); + break; + case PROP_MIGRATION_FLAGS: + self->priv->migration_flags = g_value_get_uint(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void +red_channel_finalize(GObject *object) +{ + RedChannel *self = RED_CHANNEL(object); + + if (self->priv->local_caps.num_common_caps) { + free(self->priv->local_caps.common_caps); + } + + if (self->priv->local_caps.num_caps) { + free(self->priv->local_caps.caps); + } + + G_OBJECT_CLASS(red_channel_parent_class)->finalize(object); } static void red_channel_client_default_peer_on_error(RedChannelClient *rcc) @@ -79,10 +205,163 @@ static void red_channel_client_default_peer_on_error(RedChannelClient *rcc) red_channel_client_disconnect(rcc); } +static void red_channel_on_output(void *opaque, int n) +{ + RedChannelClient *rcc = opaque; + RedChannel *self = red_channel_client_get_channel(rcc);; + + red_channel_client_on_output(opaque, n); + + stat_inc_counter(self->priv->reds, self->priv->out_bytes_counter, n); +} + +static void +red_channel_constructed(GObject *object) +{ + RedChannel *self = RED_CHANNEL(object); + spice_debug("%p: channel type %d id %d thread_id 0x%lx", self, + self->priv->type, self->priv->id, self->priv->thread_id); + + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); + self->priv->incoming_cb.alloc_msg_buf = + (alloc_msg_recv_buf_proc)klass->alloc_recv_buf; + self->priv->incoming_cb.release_msg_buf = + (release_msg_recv_buf_proc)klass->release_recv_buf; + self->priv->incoming_cb.handle_message = (handle_message_proc)klass->handle_message; + self->priv->incoming_cb.handle_parsed = (handle_parsed_proc)klass->handle_parsed; + self->priv->incoming_cb.parser = klass->parser; + + G_OBJECT_CLASS(red_channel_parent_class)->constructed(object); +} + +static void red_channel_client_default_connect(RedChannel *channel, RedClient *client, + RedsStream *stream, + int migration, + int num_common_caps, uint32_t *common_caps, + int num_caps, uint32_t *caps) +{ + spice_error("not implemented"); +} + +static void red_channel_client_default_disconnect(RedChannelClient *base) +{ + red_channel_client_disconnect(base); +} + +static void +red_channel_class_init(RedChannelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof (RedChannelPrivate)); + + object_class->get_property = red_channel_get_property; + object_class->set_property = red_channel_set_property; + object_class->finalize = red_channel_finalize; + object_class->constructed = red_channel_constructed; + + g_object_class_install_property(object_class, + PROP_SPICE_SERVER, + g_param_spec_pointer("spice-server", + "spice-server", + "The spice server associated with this channel", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property(object_class, + PROP_CORE_INTERFACE, + g_param_spec_pointer("core-interface", + "core-interface", + "The SpiceCoreInterface server associated with this channel", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /* FIXME: generate enums for this in spice-common? */ + g_object_class_install_property(object_class, + PROP_TYPE, + g_param_spec_int("channel-type", + "channel type", + "Type of this channel", + 0, + SPICE_END_CHANNEL, + 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property(object_class, + PROP_ID, + g_param_spec_uint("id", + "id", + "ID of this channel", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property(object_class, + PROP_HANDLE_ACKS, + g_param_spec_boolean("handle-acks", + "Handle ACKs", + "Whether this channel handles ACKs", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property(object_class, + PROP_MIGRATION_FLAGS, + g_param_spec_uint("migration-flags", + "migration flags", + "Migration flags for this channel", + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static void +red_channel_init(RedChannel *self) +{ + self->priv = CHANNEL_PRIVATE(self); + + red_channel_set_common_cap(self, SPICE_COMMON_CAP_MINI_HEADER); + self->priv->thread_id = pthread_self(); + self->priv->out_bytes_counter = 0; + + // TODO: send incoming_cb as parameters instead of duplicating? + self->priv->incoming_cb.on_error = + (on_incoming_error_proc)red_channel_client_default_peer_on_error; + self->priv->incoming_cb.on_input = red_channel_client_on_input; + self->priv->outgoing_cb.get_msg_size = red_channel_client_get_out_msg_size; + self->priv->outgoing_cb.prepare = red_channel_client_prepare_out_msg; + self->priv->outgoing_cb.on_block = red_channel_client_on_out_block; + self->priv->outgoing_cb.on_error = + (on_outgoing_error_proc)red_channel_client_default_peer_on_error; + self->priv->outgoing_cb.on_msg_done = red_channel_client_on_out_msg_done; + self->priv->outgoing_cb.on_output = red_channel_on_output; + + self->priv->client_cbs.connect = red_channel_client_default_connect; + self->priv->client_cbs.disconnect = red_channel_client_default_disconnect; + self->priv->client_cbs.migrate = red_channel_client_default_migrate; +} + + +void red_channel_receive(RedChannel *channel) +{ + g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_receive, NULL); +} + void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc) { spice_assert(rcc); - channel->clients = g_list_prepend(channel->clients, rcc); + channel->priv->clients = g_list_prepend(channel->priv->clients, rcc); } int red_channel_test_remote_common_cap(RedChannel *channel, uint32_t cap) @@ -137,7 +416,7 @@ gboolean red_client_seamless_migration_done_for_channel(RedClient *client) int red_channel_is_waiting_for_migrate_data(RedChannel *channel) { RedChannelClient *rcc; - guint n_clients = g_list_length(channel->clients); + guint n_clients = g_list_length(channel->priv->clients); if (!red_channel_is_connected(channel)) { return FALSE; @@ -147,186 +426,42 @@ int red_channel_is_waiting_for_migrate_data(RedChannel *channel) return FALSE; } spice_assert(n_clients == 1); - rcc = g_list_nth_data(channel->clients, 0); + rcc = g_list_nth_data(channel->priv->clients, 0); return red_channel_client_is_waiting_for_migrate_data(rcc); } -static void red_channel_client_default_connect(RedChannel *channel, RedClient *client, - RedsStream *stream, - int migration, - int num_common_caps, uint32_t *common_caps, - int num_caps, uint32_t *caps) -{ - spice_error("not implemented"); -} - -static void red_channel_client_default_disconnect(RedChannelClient *base) -{ - red_channel_client_disconnect(base); -} - -RedChannel *red_channel_create(int size, - RedsState *reds, - const SpiceCoreInterfaceInternal *core, - uint32_t type, uint32_t id, - int handle_acks, - channel_handle_message_proc handle_message, - const ChannelCbs *channel_cbs, - uint32_t migration_flags) -{ - RedChannel *channel; - ClientCbs client_cbs = { NULL, }; - - spice_assert(size >= sizeof(*channel)); - spice_assert(channel_cbs->config_socket && channel_cbs->on_disconnect && handle_message && - channel_cbs->alloc_recv_buf); - spice_assert(channel_cbs->handle_migrate_data || - !(migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER)); - channel = spice_malloc0(size); - channel->type = type; - channel->id = id; - channel->refs = 1; - channel->handle_acks = handle_acks; - channel->migration_flags = migration_flags; - channel->channel_cbs = *channel_cbs; - - channel->reds = reds; - channel->core = core; - - // TODO: send incoming_cb as parameters instead of duplicating? - channel->incoming_cb.alloc_msg_buf = (alloc_msg_recv_buf_proc)channel_cbs->alloc_recv_buf; - channel->incoming_cb.release_msg_buf = (release_msg_recv_buf_proc)channel_cbs->release_recv_buf; - channel->incoming_cb.handle_message = (handle_message_proc)handle_message; - channel->incoming_cb.on_error = - (on_incoming_error_proc)red_channel_client_default_peer_on_error; - channel->incoming_cb.on_input = red_channel_client_on_input; - channel->outgoing_cb.get_msg_size = red_channel_client_get_out_msg_size; - channel->outgoing_cb.prepare = red_channel_client_prepare_out_msg; - channel->outgoing_cb.on_block = red_channel_client_on_out_block; - channel->outgoing_cb.on_error = - (on_outgoing_error_proc)red_channel_client_default_peer_on_error; - channel->outgoing_cb.on_msg_done = red_channel_client_on_out_msg_done; - channel->outgoing_cb.on_output = red_channel_client_on_output; - - client_cbs.connect = red_channel_client_default_connect; - client_cbs.disconnect = red_channel_client_default_disconnect; - client_cbs.migrate = red_channel_client_default_migrate; - - red_channel_register_client_cbs(channel, &client_cbs, NULL); - red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER); - - channel->thread_id = pthread_self(); - - channel->out_bytes_counter = 0; - - spice_debug("channel type %d id %d thread_id 0x%lx", - channel->type, channel->id, channel->thread_id); - return channel; -} - -// TODO: red_worker can use this one -static void dummy_watch_update_mask(SpiceWatch *watch, int event_mask) -{ -} - -static SpiceWatch *dummy_watch_add(const SpiceCoreInterfaceInternal *iface, - int fd, int event_mask, SpiceWatchFunc func, void *opaque) -{ - return NULL; // apparently allowed? -} - -static void dummy_watch_remove(SpiceWatch *watch) -{ -} - -// TODO: actually, since I also use channel_client_dummy, no need for core. Can be NULL -static const SpiceCoreInterfaceInternal dummy_core = { - .watch_update_mask = dummy_watch_update_mask, - .watch_add = dummy_watch_add, - .watch_remove = dummy_watch_remove, -}; - -RedChannel *red_channel_create_dummy(int size, RedsState *reds, uint32_t type, uint32_t id) -{ - RedChannel *channel; - ClientCbs client_cbs = { NULL, }; - - spice_assert(size >= sizeof(*channel)); - channel = spice_malloc0(size); - channel->type = type; - channel->id = id; - channel->refs = 1; - channel->reds = reds; - channel->core = &dummy_core; - client_cbs.connect = red_channel_client_default_connect; - client_cbs.disconnect = red_channel_client_default_disconnect; - client_cbs.migrate = red_channel_client_default_migrate; - - red_channel_register_client_cbs(channel, &client_cbs, NULL); - red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER); - - channel->thread_id = pthread_self(); - spice_debug("channel type %d id %d thread_id 0x%lx", - channel->type, channel->id, channel->thread_id); - - channel->out_bytes_counter = 0; - - return channel; -} - -static int do_nothing_handle_message(RedChannelClient *rcc, - uint16_t type, - uint32_t size, - uint8_t *msg) -{ - return TRUE; -} - -RedChannel *red_channel_create_parser(int size, - RedsState *reds, - const SpiceCoreInterfaceInternal *core, - uint32_t type, uint32_t id, - int handle_acks, - spice_parse_channel_func_t parser, - channel_handle_parsed_proc handle_parsed, - const ChannelCbs *channel_cbs, - uint32_t migration_flags) +void red_channel_set_stat_node(RedChannel *channel, StatNodeRef stat) { - RedChannel *channel = red_channel_create(size, reds, core, type, id, - handle_acks, - do_nothing_handle_message, - channel_cbs, - migration_flags); - channel->incoming_cb.handle_parsed = (handle_parsed_proc)handle_parsed; - channel->incoming_cb.parser = parser; + spice_return_if_fail(channel != NULL); + spice_return_if_fail(channel->priv->stat == 0); - return channel; +#ifdef RED_STATISTICS + channel->priv->stat = stat; + channel->priv->out_bytes_counter = stat_add_counter(channel->priv->reds, stat, "out_bytes", TRUE); +#endif } -void red_channel_set_stat_node(RedChannel *channel, StatNodeRef stat) +StatNodeRef red_channel_get_stat_node(RedChannel *channel) { - spice_return_if_fail(channel != NULL); - spice_return_if_fail(channel->stat == 0); - #ifdef RED_STATISTICS - channel->stat = stat; - channel->out_bytes_counter = stat_add_counter(channel->reds, stat, "out_bytes", TRUE); + return channel->priv->stat; #endif + return 0; } void red_channel_register_client_cbs(RedChannel *channel, const ClientCbs *client_cbs, gpointer cbs_data) { - spice_assert(client_cbs->connect || channel->type == SPICE_CHANNEL_MAIN); - channel->client_cbs.connect = client_cbs->connect; + spice_assert(client_cbs->connect || channel->priv->type == SPICE_CHANNEL_MAIN); + channel->priv->client_cbs.connect = client_cbs->connect; if (client_cbs->disconnect) { - channel->client_cbs.disconnect = client_cbs->disconnect; + channel->priv->client_cbs.disconnect = client_cbs->disconnect; } if (client_cbs->migrate) { - channel->client_cbs.migrate = client_cbs->migrate; + channel->priv->client_cbs.migrate = client_cbs->migrate; } - channel->data = cbs_data; + channel->priv->data = cbs_data; } static void add_capability(uint32_t **caps, int *num_caps, uint32_t cap) @@ -343,32 +478,12 @@ static void add_capability(uint32_t **caps, int *num_caps, uint32_t cap) void red_channel_set_common_cap(RedChannel *channel, uint32_t cap) { - add_capability(&channel->local_caps.common_caps, &channel->local_caps.num_common_caps, cap); + add_capability(&channel->priv->local_caps.common_caps, &channel->priv->local_caps.num_common_caps, cap); } void red_channel_set_cap(RedChannel *channel, uint32_t cap) { - add_capability(&channel->local_caps.caps, &channel->local_caps.num_caps, cap); -} - -void red_channel_ref(RedChannel *channel) -{ - channel->refs++; -} - -void red_channel_unref(RedChannel *channel) -{ - if (--channel->refs == 0) { - if (channel->local_caps.num_common_caps) { - free(channel->local_caps.common_caps); - } - - if (channel->local_caps.num_caps) { - free(channel->local_caps.caps); - } - - free(channel); - } + add_capability(&channel->priv->local_caps.caps, &channel->priv->local_caps.num_caps, cap); } void red_channel_destroy(RedChannel *channel) @@ -377,13 +492,13 @@ void red_channel_destroy(RedChannel *channel) return; } - g_list_foreach(channel->clients, (GFunc)red_channel_client_destroy, NULL); - red_channel_unref(channel); + g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_destroy, NULL); + g_object_unref(channel); } void red_channel_send(RedChannel *channel) { - g_list_foreach(channel->clients, (GFunc)red_channel_client_send, NULL); + g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_send, NULL); } void red_channel_push(RedChannel *channel) @@ -392,14 +507,14 @@ void red_channel_push(RedChannel *channel) return; } - g_list_foreach(channel->clients, (GFunc)red_channel_client_push, NULL); + g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_push, NULL); } // TODO: this function doesn't make sense because the window should be client (WAN/LAN) // specific void red_channel_init_outgoing_messages_window(RedChannel *channel) { - g_list_foreach(channel->clients, (GFunc)red_channel_client_init_outgoing_messages_window, NULL); + g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_init_outgoing_messages_window, NULL); } static void red_channel_client_pipe_add_type_proxy(gpointer data, gpointer user_data) @@ -410,7 +525,7 @@ static void red_channel_client_pipe_add_type_proxy(gpointer data, gpointer user_ void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type) { - g_list_foreach(channel->clients, red_channel_client_pipe_add_type_proxy, + g_list_foreach(channel->priv->clients, red_channel_client_pipe_add_type_proxy, GINT_TO_POINTER(pipe_item_type)); } @@ -422,12 +537,12 @@ static void red_channel_client_pipe_add_empty_msg_proxy(gpointer data, gpointer void red_channel_pipes_add_empty_msg(RedChannel *channel, int msg_type) { - g_list_foreach(channel->clients, red_channel_client_pipe_add_empty_msg_proxy, GINT_TO_POINTER(msg_type)); + g_list_foreach(channel->priv->clients, red_channel_client_pipe_add_empty_msg_proxy, GINT_TO_POINTER(msg_type)); } int red_channel_is_connected(RedChannel *channel) { - return channel && channel->clients; + return channel && channel->priv->clients; } void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc) @@ -435,19 +550,19 @@ void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc) GList *link; g_return_if_fail(channel == red_channel_client_get_channel(rcc)); - if (!pthread_equal(pthread_self(), channel->thread_id)) { + if (!pthread_equal(pthread_self(), channel->priv->thread_id)) { spice_warning("channel type %d id %d - " "channel->thread_id (0x%lx) != pthread_self (0x%lx)." "If one of the threads is != io-thread && != vcpu-thread, " "this might be a BUG", - channel->type, channel->id, - channel->thread_id, pthread_self()); + channel->priv->type, channel->priv->id, + channel->priv->thread_id, pthread_self()); } spice_return_if_fail(channel); - link = g_list_find(channel->clients, rcc); + link = g_list_find(channel->priv->clients, rcc); spice_return_if_fail(link != NULL); - channel->clients = g_list_remove_link(channel->clients, link); + channel->priv->clients = g_list_remove_link(channel->priv->clients, link); // TODO: should we set rcc->channel to NULL??? } @@ -461,17 +576,35 @@ void red_client_remove_channel(RedChannelClient *rcc) void red_channel_disconnect(RedChannel *channel) { - g_list_foreach(channel->clients, (GFunc)red_channel_client_disconnect, NULL); + g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_disconnect, NULL); +} + +void red_channel_connect(RedChannel *channel, RedClient *client, + RedsStream *stream, int migration, int num_common_caps, + uint32_t *common_caps, int num_caps, uint32_t *caps) +{ + channel->priv->client_cbs.connect(channel, client, stream, migration, + num_common_caps, common_caps, num_caps, + caps); } void red_channel_apply_clients(RedChannel *channel, channel_client_callback cb) { - g_list_foreach(channel->clients, (GFunc)cb, NULL); + g_list_foreach(channel->priv->clients, (GFunc)cb, NULL); } void red_channel_apply_clients_data(RedChannel *channel, channel_client_callback_data cb, void *data) { - g_list_foreach(channel->clients, (GFunc)cb, data); + g_list_foreach(channel->priv->clients, (GFunc)cb, data); +} + +GList *red_channel_get_clients(RedChannel *channel) +{ + return channel->priv->clients; +} +guint red_channel_get_n_clients(RedChannel *channel) +{ + return g_list_length(channel->priv->clients); } int red_channel_all_blocked(RedChannel *channel) @@ -479,7 +612,7 @@ int red_channel_all_blocked(RedChannel *channel) GListIter iter; RedChannelClient *rcc; - if (!channel || !channel->clients) { + if (!channel || !channel->priv->clients) { return FALSE; } FOREACH_CLIENT(channel, iter, rcc) { @@ -508,10 +641,10 @@ int red_channel_get_first_socket(RedChannel *channel) RedChannelClient *rcc; RedsStream *stream; - if (!channel || !channel->clients) { + if (!channel || !channel->priv->clients) { return -1; } - rcc = g_list_nth_data(channel->clients, 0); + rcc = g_list_nth_data(channel->priv->clients, 0); stream = red_channel_client_get_stream(rcc); return stream->socket; @@ -600,7 +733,7 @@ void red_client_migrate(RedClient *client) FOREACH_CHANNEL_CLIENT(client, iter, rcc) { channel = red_channel_client_get_channel(rcc); if (red_channel_client_is_connected(rcc)) { - channel->client_cbs.migrate(rcc); + channel->priv->client_cbs.migrate(rcc); } } } @@ -629,7 +762,7 @@ void red_client_destroy(RedClient *client) // to wait for disconnection) // TODO: should we go back to async. For this we need to use // ref count for channel clients. - channel->client_cbs.disconnect(rcc); + channel->priv->client_cbs.disconnect(rcc); spice_assert(red_channel_client_pipe_is_empty(rcc)); spice_assert(red_channel_client_no_item_being_sent(rcc)); red_channel_client_destroy(rcc); @@ -647,7 +780,7 @@ RedChannelClient *red_client_get_channel(RedClient *client, int type, int id) FOREACH_CHANNEL_CLIENT(client, iter, rcc) { RedChannel *channel; channel = red_channel_client_get_channel(rcc); - if (channel->type == type && channel->id == id) { + if (channel->priv->type == type && channel->priv->id == id) { ret = rcc; break; } @@ -847,5 +980,99 @@ int red_channel_wait_all_sent(RedChannel *channel, RedsState* red_channel_get_server(RedChannel *channel) { - return channel->reds; + return channel->priv->reds; +} + +SpiceCoreInterfaceInternal* red_channel_get_core_interface(RedChannel *channel) +{ + return channel->priv->core; +} + +int red_channel_config_socket(RedChannel *self, RedChannelClient *rcc) +{ + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); + g_return_val_if_fail(klass->config_socket, FALSE); + + return klass->config_socket(rcc); +} + +void red_channel_on_disconnect(RedChannel *self, RedChannelClient *rcc) +{ + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); + g_return_if_fail(klass->on_disconnect); + + klass->on_disconnect(rcc); +} + +void red_channel_send_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem *item) +{ + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); + g_return_if_fail(klass->send_item); + + klass->send_item(rcc, item); +} + +uint8_t* red_channel_alloc_recv_buf(RedChannel *self, RedChannelClient *rcc, + uint16_t type, uint32_t size) +{ + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); + g_return_val_if_fail(klass->alloc_recv_buf, NULL); + + return klass->alloc_recv_buf(rcc, type, size); +} + +void red_channel_release_recv_buf(RedChannel *self, RedChannelClient *rcc, + uint16_t type, uint32_t size, uint8_t *msg) +{ + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); + g_return_if_fail(klass->release_recv_buf); + + klass->release_recv_buf(rcc, type, size, msg); +} + +int red_channel_handle_migrate_flush_mark(RedChannel *self, RedChannelClient *rcc) +{ + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); + g_return_val_if_fail(klass->handle_migrate_flush_mark, FALSE); + + return klass->handle_migrate_flush_mark(rcc); +} + +int red_channel_handle_migrate_data(RedChannel *self, RedChannelClient *rcc, + uint32_t size, void *message) +{ + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); + g_return_val_if_fail(klass->handle_migrate_data, FALSE); + + return klass->handle_migrate_data(rcc, size, message); +} + +uint64_t red_channel_handle_migrate_data_get_serial(RedChannel *self, + RedChannelClient *rcc, + uint32_t size, void *message) +{ + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); + g_return_val_if_fail(klass->handle_migrate_data_get_serial, 0); + + return klass->handle_migrate_data_get_serial(rcc, size, message); +} + +IncomingHandlerInterface* red_channel_get_incoming_handler(RedChannel *self) +{ + return &self->priv->incoming_cb; +} + +OutgoingHandlerInterface* red_channel_get_outgoing_handler(RedChannel *self) +{ + return &self->priv->outgoing_cb; +} + +void red_channel_reset_thread_id(RedChannel *self) +{ + self->priv->thread_id = pthread_self(); +} + +RedChannelCapabilities* red_channel_get_local_capabilities(RedChannel *self) +{ + return &self->priv->local_caps; } |