[Spice-devel] [PATCH spice-server v7] Convert RedChannel hierarchy to GObject
Jonathon Jongsma
jjongsma at redhat.com
Fri Oct 21 20:28:56 UTC 2016
Hopefully this version can go in. Anybody want to review? I don't feel
I should ACK it, being the primary author of the patch.
On Thu, 2016-10-20 at 17:12 +0100, Frediano Ziglio wrote:
> From: Jonathon Jongsma <jjongsma at redhat.com>
>
> ---
> server/Makefile.am | 2 +
> server/common-graphics-channel.c | 111 ++++--
> server/common-graphics-channel.h | 42 ++-
> server/cursor-channel.c | 125 +++----
> server/cursor-channel.h | 19 +-
> server/dcc-send.c | 11 +-
> server/dcc.c | 1 +
> server/dcc.h | 1 -
> server/display-channel-private.h | 76 +++++
> server/display-channel.c | 235 ++++++++++---
> server/display-channel.h | 100 ++----
> server/dummy-channel-client.c | 17 +-
> server/dummy-channel.c | 49 +++
> server/dummy-channel.h | 60 ++++
> server/inputs-channel.c | 140 +++++---
> server/inputs-channel.h | 19 +-
> server/main-channel-client.c | 38 ++-
> server/main-channel.c | 153 ++++++---
> server/main-channel.h | 32 +-
> server/red-channel-client-private.h | 19 ++
> server/red-channel-client.c | 179 ++++++----
> server/red-channel-client.h | 4 +-
> server/red-channel.c | 649 ++++++++++++++++++++++++
> ------------
> server/red-channel.h | 183 +++++-----
> server/red-parse-qxl.h | 2 +
> server/red-qxl.c | 21 +-
> server/red-replay-qxl.c | 2 +-
> server/red-worker.c | 27 +-
> server/red-worker.h | 2 -
> server/reds-private.h | 3 +-
> server/reds.c | 66 ++--
> server/smartcard.c | 138 ++++++--
> server/sound.c | 44 ++-
> server/spicevmc.c | 450 +++++++++++++++++++------
> server/stream.c | 4 +-
> 35 files changed, 2068 insertions(+), 956 deletions(-)
> create mode 100644 server/display-channel-private.h
> create mode 100644 server/dummy-channel.c
> create mode 100644 server/dummy-channel.h
>
> Changes since v6:
> - rebased on master;
> - merged acked fixup.
>
> diff --git a/server/Makefile.am b/server/Makefile.am
> index dff1ad2..7aada48 100644
> --- a/server/Makefile.am
> +++ b/server/Makefile.am
> @@ -102,6 +102,8 @@ libserver_la_SOURCES =
> \
> red-channel-client.c \
> red-channel-client.h \
> red-channel-client-private.h \
> + dummy-channel.c \
> + dummy-channel.h \
> dummy-channel-client.c \
> dummy-channel-client.h \
> red-common.h \
> diff --git a/server/common-graphics-channel.c b/server/common-
> graphics-channel.c
> index 8af1c10..e3a3ded 100644
> --- a/server/common-graphics-channel.c
> +++ b/server/common-graphics-channel.c
> @@ -29,6 +29,11 @@
>
> #define CHANNEL_RECEIVE_BUF_SIZE 1024
>
> +G_DEFINE_ABSTRACT_TYPE(CommonGraphicsChannel,
> common_graphics_channel, RED_TYPE_CHANNEL)
> +
> +#define GRAPHICS_CHANNEL_PRIVATE(o) \
> + (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_COMMON_GRAPHICS_CHANNEL,
> CommonGraphicsChannelPrivate))
> +
> struct CommonGraphicsChannelPrivate
> {
> QXLInstance *qxl;
> @@ -43,7 +48,7 @@ struct CommonGraphicsChannelPrivate
> static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc,
> uint16_t type, uint32_t size)
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> - CommonGraphicsChannel *common = SPICE_CONTAINEROF(channel,
> CommonGraphicsChannel, base);
> + CommonGraphicsChannel *common =
> COMMON_GRAPHICS_CHANNEL(channel);
>
> /* SPICE_MSGC_MIGRATE_DATA is the only client message whose size
> is dynamic */
> if (type == SPICE_MSGC_MIGRATE_DATA) {
> @@ -65,6 +70,48 @@ static void
> common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32
> }
> }
>
> +
> +enum {
> + PROP0,
> + PROP_QXL
> +};
> +
> +static void
> +common_graphics_channel_get_property(GObject *object,
> + guint property_id,
> + GValue *value,
> + GParamSpec *pspec)
> +{
> + CommonGraphicsChannel *self = COMMON_GRAPHICS_CHANNEL(object);
> +
> + switch (property_id)
> + {
> + case PROP_QXL:
> + g_value_set_pointer(value, self->priv->qxl);
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id,
> pspec);
> + }
> +}
> +
> +static void
> +common_graphics_channel_set_property(GObject *object,
> + guint property_id,
> + const GValue *value,
> + GParamSpec *pspec)
> +{
> + CommonGraphicsChannel *self = COMMON_GRAPHICS_CHANNEL(object);
> +
> + switch (property_id)
> + {
> + case PROP_QXL:
> + self->priv->qxl = g_value_get_pointer(value);
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id,
> pspec);
> + }
> +}
> +
> int common_channel_config_socket(RedChannelClient *rcc)
> {
> RedClient *client = red_channel_client_get_client(rcc);
> @@ -106,40 +153,36 @@ int
> common_channel_config_socket(RedChannelClient *rcc)
> return TRUE;
> }
>
> -CommonGraphicsChannel* common_graphics_channel_new(RedsState
> *server,
> - QXLInstance *qxl,
> - const
> SpiceCoreInterfaceInternal *core,
> - int size,
> uint32_t channel_type,
> - int
> migration_flags,
> - ChannelCbs
> *channel_cbs,
> - channel_handle_pa
> rsed_proc handle_parsed)
> +
> +static void
> +common_graphics_channel_class_init(CommonGraphicsChannelClass
> *klass)
> +{
> + GObjectClass *object_class = G_OBJECT_CLASS(klass);
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + g_type_class_add_private(klass,
> sizeof(CommonGraphicsChannelPrivate));
> +
> + object_class->get_property =
> common_graphics_channel_get_property;
> + object_class->set_property =
> common_graphics_channel_set_property;
> +
> + channel_class->config_socket = common_channel_config_socket;
> + channel_class->alloc_recv_buf = common_alloc_recv_buf;
> + channel_class->release_recv_buf = common_release_recv_buf;
> +
> + g_object_class_install_property(object_class,
> + PROP_QXL,
> + g_param_spec_pointer("qxl",
> + "qxl",
> + "QXLInstanc
> e for this channel",
> + G_PARAM_REA
> DWRITE |
> + G_PARAM_CON
> STRUCT_ONLY |
> + G_PARAM_STA
> TIC_STRINGS));
> +}
> +
> +static void
> +common_graphics_channel_init(CommonGraphicsChannel *self)
> {
> - RedChannel *channel = NULL;
> - CommonGraphicsChannel *common;
> -
> - spice_return_val_if_fail(channel_cbs, NULL);
> - spice_return_val_if_fail(!channel_cbs->alloc_recv_buf, NULL);
> - spice_return_val_if_fail(!channel_cbs->release_recv_buf, NULL);
> -
> - if (!channel_cbs->config_socket)
> - channel_cbs->config_socket = common_channel_config_socket;
> - channel_cbs->alloc_recv_buf = common_alloc_recv_buf;
> - channel_cbs->release_recv_buf = common_release_recv_buf;
> -
> - channel = red_channel_create_parser(size, server,
> - core, channel_type,
> - qxl->id, TRUE /* handle_acks
> */,
> - spice_get_client_channel_par
> ser(channel_type, NULL),
> - handle_parsed,
> - channel_cbs,
> - migration_flags);
> - spice_return_val_if_fail(channel, NULL);
> -
> - common = COMMON_GRAPHICS_CHANNEL(channel);
> - /* FIXME remove leak */
> - common->priv = g_new0(CommonGraphicsChannelPrivate, 1);
> - common->priv->qxl = qxl;
> - return common;
> + self->priv = GRAPHICS_CHANNEL_PRIVATE(self);
> }
>
> void
> common_graphics_channel_set_during_target_migrate(CommonGraphicsChann
> el *self, gboolean value)
> diff --git a/server/common-graphics-channel.h b/server/common-
> graphics-channel.h
> index 97cd63b..a8c3f3d 100644
> --- a/server/common-graphics-channel.h
> +++ b/server/common-graphics-channel.h
> @@ -18,21 +18,47 @@
> #ifndef _COMMON_GRAPHICS_CHANNEL_H
> #define _COMMON_GRAPHICS_CHANNEL_H
>
> +#include <glib-object.h>
> +
> #include "red-channel.h"
> #include "red-channel-client.h"
>
> +G_BEGIN_DECLS
> +
> int common_channel_config_socket(RedChannelClient *rcc);
>
> #define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30)
>
> +#define TYPE_COMMON_GRAPHICS_CHANNEL
> common_graphics_channel_get_type()
> +
> +#define COMMON_GRAPHICS_CHANNEL(obj) \
> + (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_COMMON_GRAPHICS_CHANNEL,
> CommonGraphicsChannel))
> +#define COMMON_GRAPHICS_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_COMMON_GRAPHICS_CHANNEL,
> CommonGraphicsChannelClass))
> +#define COMMON_IS_GRAPHICS_CHANNEL(obj) \
> + (G_TYPE_CHECK_INSTANCE_TYPE((obj),
> TYPE_COMMON_GRAPHICS_CHANNEL))
> +#define COMMON_IS_GRAPHICS_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_COMMON_GRAPHICS_CHANNEL))
> +#define COMMON_GRAPHICS_CHANNEL_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_COMMON_GRAPHICS_CHANNEL,
> CommonGraphicsChannelClass))
> +
> +typedef struct CommonGraphicsChannel CommonGraphicsChannel;
> +typedef struct CommonGraphicsChannelClass
> CommonGraphicsChannelClass;
> typedef struct CommonGraphicsChannelPrivate
> CommonGraphicsChannelPrivate;
> -typedef struct CommonGraphicsChannel {
> - RedChannel base; // Must be the first thing
> +
> +struct CommonGraphicsChannel
> +{
> + RedChannel parent;
>
> CommonGraphicsChannelPrivate *priv;
> -} CommonGraphicsChannel;
> +};
> +
> +struct CommonGraphicsChannelClass
> +{
> + RedChannelClass parent_class;
> +};
>
> -#define COMMON_GRAPHICS_CHANNEL(Channel)
> ((CommonGraphicsChannel*)(Channel))
> +GType common_graphics_channel_get_type(void) G_GNUC_CONST;
>
> void
> common_graphics_channel_set_during_target_migrate(CommonGraphicsChann
> el *self, gboolean value);
> gboolean
> common_graphics_channel_get_during_target_migrate(CommonGraphicsChann
> el *self);
> @@ -76,12 +102,6 @@ static inline void red_pipes_add_verb(RedChannel
> *channel, uint16_t verb)
> red_channel_apply_clients_data(channel, red_pipe_add_verb_proxy,
> GUINT_TO_POINTER(verb));
> }
>
> -CommonGraphicsChannel* common_graphics_channel_new(RedsState
> *server,
> - QXLInstance *qxl,
> - const
> SpiceCoreInterfaceInternal *core,
> - int size,
> uint32_t channel_type,
> - int
> migration_flags,
> - ChannelCbs
> *channel_cbs,
> - channel_handle_pa
> rsed_proc handle_parsed);
> +G_END_DECLS
>
> #endif /* _COMMON_GRAPHICS_CHANNEL_H */
> diff --git a/server/cursor-channel.c b/server/cursor-channel.c
> index cfaf55d..dbe3dfc 100644
> --- a/server/cursor-channel.c
> +++ b/server/cursor-channel.c
> @@ -28,8 +28,6 @@
> #include "reds.h"
> #include "red-qxl.h"
>
> -#define CURSOR_CHANNEL(channel) ((CursorChannel*)(channel))
> -
> typedef struct CursorItem {
> QXLInstance *qxl;
> int refs;
> @@ -38,13 +36,10 @@ typedef struct CursorItem {
>
> G_STATIC_ASSERT(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE);
>
> -typedef struct RedCursorPipeItem {
> - RedPipeItem base;
> - CursorItem *cursor_item;
> -} RedCursorPipeItem;
> +struct CursorChannel
> +{
> + CommonGraphicsChannel parent;
>
> -typedef struct CursorChannelPrivate CursorChannelPrivate;
> -struct CursorChannelPrivate {
> CursorItem *item;
> int cursor_visible;
> SpicePoint16 cursor_position;
> @@ -53,12 +48,18 @@ struct CursorChannelPrivate {
> uint32_t mouse_mode;
> };
>
> -struct CursorChannel {
> - CommonGraphicsChannel common; // Must be the first thing
> -
> - CursorChannelPrivate priv[1];
> +struct CursorChannelClass
> +{
> + CommonGraphicsChannelClass parent_class;
> };
>
> +typedef struct RedCursorPipeItem {
> + RedPipeItem base;
> + CursorItem *cursor_item;
> +} RedCursorPipeItem;
> +
> +G_DEFINE_TYPE(CursorChannel, cursor_channel,
> TYPE_COMMON_GRAPHICS_CHANNEL)
> +
> static void cursor_pipe_item_free(RedPipeItem *pipe_item);
>
> static CursorItem *cursor_item_new(QXLInstance *qxl, RedCursorCmd
> *cmd)
> @@ -105,10 +106,10 @@ static void cursor_item_unref(CursorItem *item)
>
> static void cursor_set_item(CursorChannel *cursor, CursorItem *item)
> {
> - if (cursor->priv->item)
> - cursor_item_unref(cursor->priv->item);
> + if (cursor->item)
> + cursor_item_unref(cursor->item);
>
> - cursor->priv->item = item ? cursor_item_ref(item) : NULL;
> + cursor->item = item ? cursor_item_ref(item) : NULL;
> }
>
> static RedPipeItem *new_cursor_pipe_item(RedChannelClient *rcc, void
> *data, int num)
> @@ -197,12 +198,12 @@ static void
> red_marshall_cursor_init(CursorChannelClient *ccc, SpiceMarshaller *
> cursor_channel =
> CURSOR_CHANNEL(red_channel_client_get_channel(rcc));
>
> red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INIT,
> NULL);
> - msg.visible = cursor_channel->priv->cursor_visible;
> - msg.position = cursor_channel->priv->cursor_position;
> - msg.trail_length = cursor_channel->priv->cursor_trail_length;
> - msg.trail_frequency = cursor_channel->priv-
> >cursor_trail_frequency;
> + msg.visible = cursor_channel->cursor_visible;
> + msg.position = cursor_channel->cursor_position;
> + msg.trail_length = cursor_channel->cursor_trail_length;
> + msg.trail_frequency = cursor_channel->cursor_trail_frequency;
>
> - cursor_fill(ccc, &msg.cursor, cursor_channel->priv->item,
> &info);
> + cursor_fill(ccc, &msg.cursor, cursor_channel->item, &info);
> spice_marshall_msg_cursor_init(base_marshaller, &msg);
> add_buf_from_info(base_marshaller, &info);
> }
> @@ -212,8 +213,7 @@ static void cursor_marshall(CursorChannelClient
> *ccc,
> RedCursorPipeItem *cursor_pipe_item)
> {
> RedChannelClient *rcc = RED_CHANNEL_CLIENT(ccc);
> - CursorChannel *cursor_channel =
> SPICE_CONTAINEROF(red_channel_client_get_channel(rcc),
> - CursorChannel,
> common.base);
> + CursorChannel *cursor_channel =
> CURSOR_CHANNEL(red_channel_client_get_channel(rcc));
> CursorItem *item = cursor_pipe_item->cursor_item;
> RedPipeItem *pipe_item = &cursor_pipe_item->base;
> RedCursorCmd *cmd;
> @@ -237,7 +237,7 @@ static void cursor_marshall(CursorChannelClient
> *ccc,
>
> red_channel_client_init_send_data(rcc,
> SPICE_MSG_CURSOR_SET, pipe_item);
> cursor_set.position = cmd->u.set.position;
> - cursor_set.visible = cursor_channel->priv-
> >cursor_visible;
> + cursor_set.visible = cursor_channel->cursor_visible;
>
> cursor_fill(ccc, &cursor_set.cursor, item, &info);
> spice_marshall_msg_cursor_set(m, &cursor_set);
> @@ -307,24 +307,14 @@ static void
> cursor_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_it
> CursorChannel* cursor_channel_new(RedsState *server, QXLInstance
> *qxl,
> const SpiceCoreInterfaceInternal
> *core)
> {
> - CursorChannel *cursor_channel;
> - CommonGraphicsChannel *channel = NULL;
> - ChannelCbs cbs = {
> - .on_disconnect = cursor_channel_client_on_disconnect,
> - .send_item = cursor_channel_send_item,
> - };
> -
> spice_info("create cursor channel");
> - channel = common_graphics_channel_new(server, qxl, core,
> - sizeof(CursorChannel),
> - SPICE_CHANNEL_CURSOR, 0,
> - &cbs,
> red_channel_client_handle_message);
> -
> - cursor_channel = CURSOR_CHANNEL(channel);
> - cursor_channel->priv->cursor_visible = TRUE;
> - cursor_channel->priv->mouse_mode = SPICE_MOUSE_MODE_SERVER;
> -
> - return cursor_channel;
> + return g_object_new(TYPE_CURSOR_CHANNEL,
> + "spice-server", server,
> + "core-interface", core,
> + "channel-type", SPICE_CHANNEL_CURSOR,
> + "migration-flags", 0,
> + "qxl", qxl,
> + NULL);
> }
>
> void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd
> *cursor_cmd)
> @@ -341,31 +331,31 @@ void cursor_channel_process_cmd(CursorChannel
> *cursor, RedCursorCmd *cursor_cmd)
>
> switch (cursor_cmd->type) {
> case QXL_CURSOR_SET:
> - cursor->priv->cursor_visible = cursor_cmd->u.set.visible;
> + cursor->cursor_visible = cursor_cmd->u.set.visible;
> cursor_set_item(cursor, cursor_item);
> break;
> case QXL_CURSOR_MOVE:
> - cursor_show = !cursor->priv->cursor_visible;
> - cursor->priv->cursor_visible = TRUE;
> - cursor->priv->cursor_position = cursor_cmd->u.position;
> + cursor_show = !cursor->cursor_visible;
> + cursor->cursor_visible = TRUE;
> + cursor->cursor_position = cursor_cmd->u.position;
> break;
> case QXL_CURSOR_HIDE:
> - cursor->priv->cursor_visible = FALSE;
> + cursor->cursor_visible = FALSE;
> break;
> case QXL_CURSOR_TRAIL:
> - cursor->priv->cursor_trail_length = cursor_cmd-
> >u.trail.length;
> - cursor->priv->cursor_trail_frequency = cursor_cmd-
> >u.trail.frequency;
> + cursor->cursor_trail_length = cursor_cmd->u.trail.length;
> + cursor->cursor_trail_frequency = cursor_cmd-
> >u.trail.frequency;
> break;
> default:
> spice_warning("invalid cursor command %u", cursor_cmd-
> >type);
> return;
> }
>
> - if (red_channel_is_connected(&cursor->common.base) &&
> - (cursor->priv->mouse_mode == SPICE_MOUSE_MODE_SERVER
> + if (red_channel_is_connected(RED_CHANNEL(cursor)) &&
> + (cursor->mouse_mode == SPICE_MOUSE_MODE_SERVER
> || cursor_cmd->type != QXL_CURSOR_MOVE
> || cursor_show)) {
> - red_channel_pipes_new_add(&cursor->common.base,
> + red_channel_pipes_new_add(RED_CHANNEL(cursor),
> new_cursor_pipe_item,
> cursor_item);
> }
>
> @@ -374,21 +364,21 @@ void cursor_channel_process_cmd(CursorChannel
> *cursor, RedCursorCmd *cursor_cmd)
>
> void cursor_channel_reset(CursorChannel *cursor)
> {
> - RedChannel *channel = &cursor->common.base;
> + RedChannel *channel = RED_CHANNEL(cursor);
>
> spice_return_if_fail(cursor);
>
> cursor_set_item(cursor, NULL);
> - cursor->priv->cursor_visible = TRUE;
> - cursor->priv->cursor_position.x = cursor->priv-
> >cursor_position.y = 0;
> - cursor->priv->cursor_trail_length = cursor->priv-
> >cursor_trail_frequency = 0;
> + cursor->cursor_visible = TRUE;
> + cursor->cursor_position.x = cursor->cursor_position.y = 0;
> + cursor->cursor_trail_length = cursor->cursor_trail_frequency =
> 0;
>
> if (red_channel_is_connected(channel)) {
> red_channel_pipes_add_type(channel,
> RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
> if
> (!common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_C
> HANNEL(cursor))) {
> red_pipes_add_verb(channel, SPICE_MSG_CURSOR_RESET);
> }
> - if (!red_channel_wait_all_sent(&cursor->common.base,
> + if (!red_channel_wait_all_sent(channel,
> COMMON_CLIENT_TIMEOUT)) {
> red_channel_apply_clients(channel,
> red_channel_client_disconnect_
> if_pending_send);
> @@ -400,7 +390,7 @@ static void
> cursor_channel_init_client(CursorChannel *cursor, CursorChannelClien
> {
> spice_return_if_fail(cursor);
>
> - if (!red_channel_is_connected(&cursor->common.base)
> + if (!red_channel_is_connected(RED_CHANNEL(cursor))
> ||
> common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHA
> NNEL(cursor))) {
> spice_debug("during_target_migrate: skip init");
> return;
> @@ -413,7 +403,7 @@ static void
> cursor_channel_init_client(CursorChannel *cursor, CursorChannelClien
> red_channel_pipes_add_type(RED_CHANNEL(cursor),
> RED_PIPE_ITEM_TYPE_CURSOR_INIT);
> }
>
> -void cursor_channel_init(CursorChannel *cursor)
> +void cursor_channel_do_init(CursorChannel *cursor)
> {
> cursor_channel_init_client(cursor, NULL);
> }
> @@ -422,7 +412,7 @@ void cursor_channel_set_mouse_mode(CursorChannel
> *cursor, uint32_t mode)
> {
> spice_return_if_fail(cursor);
>
> - cursor->priv->mouse_mode = mode;
> + cursor->mouse_mode = mode;
> }
>
> void cursor_channel_connect(CursorChannel *cursor, RedClient
> *client, RedsStream *stream,
> @@ -447,3 +437,22 @@ void cursor_channel_connect(CursorChannel
> *cursor, RedClient *client, RedsStream
>
> cursor_channel_init_client(cursor, ccc);
> }
> +
> +static void
> +cursor_channel_class_init(CursorChannelClass *klass)
> +{
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + channel_class->parser =
> spice_get_client_channel_parser(SPICE_CHANNEL_CURSOR, NULL);
> + channel_class->handle_parsed =
> red_channel_client_handle_message;
> +
> + channel_class->on_disconnect
> = cursor_channel_client_on_disconnect;
> + channel_class->send_item = cursor_channel_send_item;
> +}
> +
> +static void
> +cursor_channel_init(CursorChannel *self)
> +{
> + self->cursor_visible = TRUE;
> + self->mouse_mode = SPICE_MOUSE_MODE_SERVER;
> +}
> diff --git a/server/cursor-channel.h b/server/cursor-channel.h
> index bbc4868..26b2cbb 100644
> --- a/server/cursor-channel.h
> +++ b/server/cursor-channel.h
> @@ -21,12 +21,27 @@
> #include "common-graphics-channel.h"
> #include "red-parse-qxl.h"
>
> +G_BEGIN_DECLS
> +
> /**
> * This type it's a RedChannel class which implement cursor (mouse)
> * movements.
> * A pointer to CursorChannel can be converted to a RedChannel.
> */
> typedef struct CursorChannel CursorChannel;
> +typedef struct CursorChannelClass CursorChannelClass;
> +
> +#define TYPE_CURSOR_CHANNEL cursor_channel_get_type()
> +
> +#define CURSOR_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),
> TYPE_CURSOR_CHANNEL, CursorChannel))
> +#define CURSOR_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_CURSOR_CHANNEL,
> CursorChannelClass))
> +#define IS_CURSOR_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),
> TYPE_CURSOR_CHANNEL))
> +#define IS_CURSOR_CHANNEL_CLASS(klass)
> (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_CURSOR_CHANNEL))
> +#define CURSOR_CHANNEL_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_CURSOR_CHANNEL,
> CursorChannelClass))
> +
> +GType cursor_channel_get_type(void) G_GNUC_CONST;
>
> /**
> * Create CursorChannel.
> @@ -48,7 +63,7 @@
> CursorChannel* cursor_channel_new (RedsState *server,
> QXLInstance
> */
> void cursor_channel_disconnect (CursorChannel
> *cursor);
> void cursor_channel_reset (CursorChannel
> *cursor);
> -void cursor_channel_init (CursorChannel
> *cursor);
> +void cursor_channel_do_init (CursorChannel
> *cursor);
> void cursor_channel_process_cmd (CursorChannel
> *cursor, RedCursorCmd *cursor_cmd);
> void cursor_channel_set_mouse_mode(CursorChannel
> *cursor, uint32_t mode);
>
> @@ -70,4 +85,6 @@
> void cursor_channel_connect (CursorChannel
> *cursor, RedClien
> */
> void cursor_channel_client_migrate(RedChannelClient
> *client);
>
> +G_END_DECLS
> +
> #endif /* CURSOR_CHANNEL_H_ */
> diff --git a/server/dcc-send.c b/server/dcc-send.c
> index e33f428..ef67f97 100644
> --- a/server/dcc-send.c
> +++ b/server/dcc-send.c
> @@ -20,7 +20,7 @@
> #endif
>
> #include "dcc-private.h"
> -#include "display-channel.h"
> +#include "display-channel-private.h"
> #include "red-channel-client-private.h"
>
> #include <common/marshaller.h>
> @@ -185,8 +185,9 @@ static void
> red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
> SpiceImage *image,
> SpiceImage *io_image,
> int is_lossy)
> {
> + DisplayChannel *display_channel =
> + DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
> DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc);
> - DisplayChannel *display_channel = DCC_TO_DC(dcc);
>
> if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
> spice_assert(image->descriptor.width * image-
> >descriptor.height > 0);
> @@ -1817,7 +1818,7 @@ static void
> display_channel_marshall_migrate_data(RedChannelClient *rcc,
> ImageEncoders *encoders = dcc_get_encoders(dcc);
> SpiceMigrateDataDisplay display_data = {0,};
>
> - display_channel = DCC_TO_DC(dcc);
> + display_channel =
> DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
>
> red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA,
> NULL);
> spice_marshaller_add_uint32(base_marshaller,
> SPICE_MIGRATE_DATA_DISPLAY_MAGIC);
> @@ -2120,8 +2121,8 @@ static void
> marshall_qxl_drawable(RedChannelClient *rcc,
> spice_return_if_fail(rcc);
>
> Drawable *item = dpi->drawable;
> - DisplayChannel *display =
> SPICE_CONTAINEROF(red_channel_client_get_channel(rcc),
> - DisplayChannel,
> common.base);
> + DisplayChannel *display =
> + DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
>
> spice_return_if_fail(display);
> /* allow sized frames to be streamed, even if they where
> replaced by another frame, since
> diff --git a/server/dcc.c b/server/dcc.c
> index 5c05c3b..d430d43 100644
> --- a/server/dcc.c
> +++ b/server/dcc.c
> @@ -21,6 +21,7 @@
>
> #include "dcc-private.h"
> #include "display-channel.h"
> +#include "display-channel-private.h"
> #include "red-channel-client-private.h"
> #include "main-channel-client.h"
> #include "spice-server-enums.h"
> diff --git a/server/dcc.h b/server/dcc.h
> index 7a07981..e4fe788 100644
> --- a/server/dcc.h
> +++ b/server/dcc.h
> @@ -23,7 +23,6 @@
> #include "image-encoders.h"
> #include "image-cache.h"
> #include "pixmap-cache.h"
> -#include "red-worker.h"
> #include "display-limits.h"
> #include "red-channel-client.h"
>
> diff --git a/server/display-channel-private.h b/server/display-
> channel-private.h
> new file mode 100644
> index 0000000..38330da
> --- /dev/null
> +++ b/server/display-channel-private.h
> @@ -0,0 +1,76 @@
> +/*
> + Copyright (C) 2009-2015 Red Hat, Inc.
> +
> + This library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later
> version.
> +
> + This library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with this library; if not, see <http://www.gnu.org/
> licenses/>.
> +*/
> +
> +#ifndef DISPLAY_CHANNEL_PRIVATE_H_
> +#define DISPLAY_CHANNEL_PRIVATE_H_
> +
> +#include "display-channel.h"
> +
> +struct DisplayChannelPrivate
> +{
> + DisplayChannel *pub;
> +
> + uint32_t bits_unique;
> +
> + MonitorsConfig *monitors_config;
> +
> + uint32_t renderer;
> + int enable_jpeg;
> + int enable_zlib_glz_wrap;
> +
> + Ring current_list; // of TreeItem
> + uint32_t current_size;
> +
> + uint32_t drawable_count;
> + _Drawable drawables[NUM_DRAWABLES];
> + _Drawable *free_drawables;
> +
> + int stream_video;
> + GArray *video_codecs;
> + uint32_t stream_count;
> + Stream streams_buf[NUM_STREAMS];
> + Stream *free_streams;
> + Ring streams;
> + ItemTrace items_trace[NUM_TRACE_ITEMS];
> + uint32_t next_item_trace;
> + uint64_t streams_size_total;
> +
> + RedSurface surfaces[NUM_SURFACES];
> + uint32_t n_surfaces;
> + SpiceImageSurfaces image_surfaces;
> +
> + ImageCache image_cache;
> +
> + int gl_draw_async_count;
> +
> +/* TODO: some day unify this, make it more runtime.. */
> + stat_info_t add_stat;
> + stat_info_t exclude_stat;
> + stat_info_t __exclude_stat;
> +#ifdef RED_WORKER_STAT
> + uint32_t add_count;
> + uint32_t add_with_shadow_count;
> +#endif
> +#ifdef RED_STATISTICS
> + uint64_t *cache_hits_counter;
> + uint64_t *add_to_cache_counter;
> + uint64_t *non_cache_counter;
> +#endif
> + ImageEncoderSharedData encoder_shared_data;
> +};
> +
> +#endif /* DISPLAY_CHANNEL_PRIVATE_H_ */
> diff --git a/server/display-channel.c b/server/display-channel.c
> index 0b8d6b5..decdfee 100644
> --- a/server/display-channel.c
> +++ b/server/display-channel.c
> @@ -20,7 +20,69 @@
>
> #include <common/sw_canvas.h>
>
> -#include "display-channel.h"
> +#include "display-channel-private.h"
> +
> +G_DEFINE_TYPE(DisplayChannel, display_channel,
> TYPE_COMMON_GRAPHICS_CHANNEL)
> +
> +enum {
> + PROP0,
> + PROP_N_SURFACES,
> + PROP_VIDEO_CODECS
> +};
> +
> +static void
> +display_channel_get_property(GObject *object,
> + guint property_id,
> + GValue *value,
> + GParamSpec *pspec)
> +{
> + DisplayChannel *self = DISPLAY_CHANNEL(object);
> +
> + switch (property_id)
> + {
> + case PROP_N_SURFACES:
> + g_value_set_uint(value, self->priv->n_surfaces);
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id,
> pspec);
> + }
> +}
> +
> +static void
> +display_channel_set_property(GObject *object,
> + guint property_id,
> + const GValue *value,
> + GParamSpec *pspec)
> +{
> + DisplayChannel *self = DISPLAY_CHANNEL(object);
> +
> + switch (property_id)
> + {
> + case PROP_N_SURFACES:
> + self->priv->n_surfaces = g_value_get_uint(value);
> + self->priv->n_surfaces = MIN(self->priv->n_surfaces,
> NUM_SURFACES);
> + break;
> + case PROP_VIDEO_CODECS:
> + if (self->priv->video_codecs) {
> + g_array_unref(self->priv->video_codecs);
> + }
> + self->priv->video_codecs =
> g_array_ref(g_value_get_boxed(value));
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id,
> pspec);
> + }
> +}
> +
> +static void
> +display_channel_finalize(GObject *object)
> +{
> + DisplayChannel *self = DISPLAY_CHANNEL(object);
> +
> + G_OBJECT_CLASS(display_channel_parent_class)->finalize(object);
> +
> + g_free(self->priv);
> + g_array_unref(self->priv->video_codecs);
> +}
>
> static void drawable_draw(DisplayChannel *display, Drawable
> *drawable);
> static Drawable *display_channel_drawable_try_new(DisplayChannel
> *display,
> @@ -43,12 +105,16 @@ void
> display_channel_compress_stats_reset(DisplayChannel *display)
> image_encoder_shared_stat_reset(&display->priv-
> >encoder_shared_data);
> }
>
> -void display_channel_compress_stats_print(const DisplayChannel
> *display_channel)
> +void display_channel_compress_stats_print(DisplayChannel
> *display_channel)
> {
> #ifdef COMPRESS_STAT
> + uint32_t id;
> +
> spice_return_if_fail(display_channel);
>
> - spice_info("==> Compression stats for display %u",
> display_channel->common.base.id);
> + g_object_get(display_channel, "id", &id, NULL);
> +
> + spice_info("==> Compression stats for display %u", id);
> image_encoder_shared_stat_print(&display_channel->priv-
> >encoder_shared_data);
> #endif
> }
> @@ -150,6 +216,11 @@ void
> display_channel_set_video_codecs(DisplayChannel *display, GArray
> *video_cod
> display->priv->video_codecs = g_array_ref(video_codecs);
> }
>
> +int display_channel_get_stream_video(DisplayChannel *display)
> +{
> + return display->priv->stream_video;
> +}
> +
> static void stop_streams(DisplayChannel *display)
> {
> Ring *ring = &display->priv->streams;
> @@ -280,7 +351,7 @@ static void
> pipes_add_drawable_after(DisplayChannel *display,
> pipes_add_drawable(display, drawable);
> return;
> }
> - if (num_other_linked != g_list_length(display-
> >common.base.clients)) {
> + if (num_other_linked !=
> red_channel_get_n_clients(RED_CHANNEL(display))) {
> GListIter iter;
> spice_debug("TODO: not O(n^2)");
> FOREACH_DCC(display, iter, dcc) {
> @@ -1115,18 +1186,18 @@ void
> display_channel_process_draw(DisplayChannel *display, RedDrawable
> *red_draw
> int display_channel_wait_for_migrate_data(DisplayChannel *display)
> {
> uint64_t end_time = spice_get_monotonic_time_ns() +
> DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT;
> - RedChannel *channel = &display->common.base;
> RedChannelClient *rcc;
> int ret = FALSE;
> + GList *clients = red_channel_get_clients(RED_CHANNEL(display));;
>
> - if (!red_channel_is_waiting_for_migrate_data(&display-
> >common.base)) {
> + if
> (!red_channel_is_waiting_for_migrate_data(RED_CHANNEL(display))) {
> return FALSE;
> }
>
> spice_debug(NULL);
> - spice_warn_if_fail(g_list_length(channel->clients) == 1);
> + spice_warn_if_fail(g_list_length(clients) == 1);
>
> - rcc = g_list_nth_data(channel->clients, 0);
> + rcc = g_list_nth_data(clients, 0);
>
> g_object_ref(rcc);
> for (;;) {
> @@ -1900,7 +1971,7 @@ static SpiceCanvas
> *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t su
>
> spice_return_val_if_fail(display_channel_validate_surface(displa
> y, surface_id), NULL);
>
> - return display->priv->surfaces[surface_id].context.canvas;
> + return p->surfaces[surface_id].context.canvas;
> }
>
> DisplayChannel* display_channel_new(RedsState *reds,
> @@ -1911,53 +1982,77 @@ DisplayChannel* display_channel_new(RedsState
> *reds,
> uint32_t n_surfaces)
> {
> DisplayChannel *display;
> - ChannelCbs cbs = {
> - .on_disconnect = on_disconnect,
> - .send_item = dcc_send_item,
> - .handle_migrate_flush_mark = handle_migrate_flush_mark,
> - .handle_migrate_data = handle_migrate_data,
> - .handle_migrate_data_get_serial =
> handle_migrate_data_get_serial,
> - .config_socket = dcc_config_socket
> - };
> +
> + /* FIXME: migrate is not used...? */
> + spice_info("create display channel");
> + display = g_object_new(TYPE_DISPLAY_CHANNEL,
> + "spice-server", reds,
> + "core-interface", core,
> + "channel-type", SPICE_CHANNEL_DISPLAY,
> + "migration-flags",
> + (SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER),
> + "qxl", qxl,
> + "n-surfaces", n_surfaces,
> + "video-codecs", video_codecs,
> + NULL);
> + if (display) {
> + display_channel_set_stream_video(display, stream_video);
> + }
> + return display;
> +}
> +
> +static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces,
> uint32_t surface_id);
> +static void drawables_init(DisplayChannel *display);
> +static void
> +display_channel_init(DisplayChannel *self)
> +{
> static SpiceImageSurfacesOps image_surfaces_ops = {
> image_surfaces_get,
> };
>
> - spice_info("create display channel");
> - display = DISPLAY_CHANNEL(common_graphics_channel_new(
> - reds, qxl, core, sizeof(*display), SPICE_CHANNEL_DISPLAY,
> - SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER,
> - &cbs, dcc_handle_message));
> - spice_return_val_if_fail(display, NULL);
> - display->priv->pub = display;
> -
> - clockid_t stat_clock = CLOCK_THREAD_CPUTIME_ID;
> - stat_init(&display->priv->add_stat, "add", stat_clock);
> - stat_init(&display->priv->exclude_stat, "exclude", stat_clock);
> - stat_init(&display->priv->__exclude_stat, "__exclude",
> stat_clock);
> -#ifdef RED_STATISTICS
> - RedChannel *channel = RED_CHANNEL(display);
> - display->priv->cache_hits_counter = stat_add_counter(reds,
> channel->stat,
> - "cache_hits
> ", TRUE);
> - display->priv->add_to_cache_counter = stat_add_counter(reds,
> channel->stat,
> - "add_to_c
> ache", TRUE);
> - display->priv->non_cache_counter = stat_add_counter(reds,
> channel->stat,
> - "non_cache",
> TRUE);
> -#endif
> - image_encoder_shared_init(&display->priv->encoder_shared_data);
> + /* must be manually allocated here since
> g_type_class_add_private() only
> + * supports structs smaller than 64k */
> + self->priv = g_new0(DisplayChannelPrivate, 1);
> + self->priv->pub = self;
>
> - display->priv->n_surfaces = MIN(n_surfaces, NUM_SURFACES);
> - display->priv->renderer = RED_RENDERER_INVALID;
> + image_encoder_shared_init(&self->priv->encoder_shared_data);
>
> - ring_init(&display->priv->current_list);
> - display->priv->image_surfaces.ops = &image_surfaces_ops;
> - drawables_init(display);
> - image_cache_init(&display->priv->image_cache);
> - display->priv->stream_video = stream_video;
> - display->priv->video_codecs = g_array_ref(video_codecs);
> - display_channel_init_streams(display);
> + ring_init(&self->priv->current_list);
> + drawables_init(self);
> + self->priv->image_surfaces.ops = &image_surfaces_ops;
> +}
>
> - return display;
> +static void
> +display_channel_constructed(GObject *object)
> +{
> + DisplayChannel *self = DISPLAY_CHANNEL(object);
> +
> + G_OBJECT_CLASS(display_channel_parent_class)-
> >constructed(object);
> +
> + spice_assert(self->priv->video_codecs);
> +
> + self->priv->renderer = RED_RENDERER_INVALID;
> +
> + stat_init(&self->priv->add_stat, "add",
> CLOCK_THREAD_CPUTIME_ID);
> + stat_init(&self->priv->exclude_stat, "exclude",
> CLOCK_THREAD_CPUTIME_ID);
> + stat_init(&self->priv->__exclude_stat, "__exclude",
> CLOCK_THREAD_CPUTIME_ID);
> +#ifdef RED_STATISTICS
> + QXLInstance *qxl = common_graphics_channel_get_qxl(&self-
> >parent);
> + RedsState *reds = red_qxl_get_server(qxl->st);
> + RedChannel *channel = RED_CHANNEL(self);
> + self->priv->cache_hits_counter =
> + stat_add_counter(reds, red_channel_get_stat_node(channel),
> + "cache_hits", TRUE);
> + self->priv->add_to_cache_counter =
> + stat_add_counter(reds, red_channel_get_stat_node(channel),
> + "add_to_cache", TRUE);
> + self->priv->non_cache_counter =
> + stat_add_counter(reds, red_channel_get_stat_node(channel),
> + "non_cache", TRUE);
> +#endif
> + image_cache_init(&self->priv->image_cache);
> + self->priv->stream_video = SPICE_STREAM_VIDEO_OFF;
> + display_channel_init_streams(self);
> }
>
> void display_channel_process_surface_cmd(DisplayChannel *display,
> @@ -2113,6 +2208,48 @@ void
> display_channel_reset_image_cache(DisplayChannel *self)
> image_cache_reset(&self->priv->image_cache);
> }
>
> +static void
> +display_channel_class_init(DisplayChannelClass *klass)
> +{
> + GObjectClass *object_class = G_OBJECT_CLASS(klass);
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + object_class->get_property = display_channel_get_property;
> + object_class->set_property = display_channel_set_property;
> + object_class->constructed = display_channel_constructed;
> + object_class->finalize = display_channel_finalize;
> +
> + channel_class->parser =
> spice_get_client_channel_parser(SPICE_CHANNEL_DISPLAY, NULL);
> + channel_class->handle_parsed = dcc_handle_message;
> +
> + channel_class->on_disconnect = on_disconnect;
> + channel_class->send_item = dcc_send_item;
> + channel_class->handle_migrate_flush_mark =
> handle_migrate_flush_mark;
> + channel_class->handle_migrate_data = handle_migrate_data;
> + channel_class->handle_migrate_data_get_serial =
> handle_migrate_data_get_serial;
> + channel_class->config_socket = dcc_config_socket;
> +
> + g_object_class_install_property(object_class,
> + PROP_N_SURFACES,
> + g_param_spec_uint("n-surfaces",
> + "number of
> surfaces",
> + "Number of
> surfaces for this channel",
> + 0, G_MAXUINT,
> + 0,
> + G_PARAM_CONSTR
> UCT_ONLY |
> + G_PARAM_READWR
> ITE |
> + G_PARAM_STATIC
> _STRINGS));
> + g_object_class_install_property(object_class,
> + PROP_VIDEO_CODECS,
> + g_param_spec_boxed("video-
> codecs",
> + "video
> codecs",
> + "Video
> Codecs",
> + G_TYPE_ARRAY,
> + G_PARAM_CONST
> RUCT_ONLY |
> + G_PARAM_WRITA
> BLE |
> + G_PARAM_STATI
> C_STRINGS));
> +}
> +
> void display_channel_debug_oom(DisplayChannel *display, const char
> *msg)
> {
> RedChannel *channel = RED_CHANNEL(display);
> diff --git a/server/display-channel.h b/server/display-channel.h
> index 3762e54..d782969 100644
> --- a/server/display-channel.h
> +++ b/server/display-channel.h
> @@ -37,7 +37,6 @@
> #include "migration-protocol.h"
> #include "main-dispatcher.h"
> #include "spice-bitmap-utils.h"
> -#include "image-cache.h"
> #include "utils.h"
> #include "tree.h"
> #include "stream.h"
> @@ -45,7 +44,36 @@
> #include "image-encoders.h"
> #include "common-graphics-channel.h"
>
> -#define DISPLAY_CHANNEL(channel) ((DisplayChannel*)(channel))
> +G_BEGIN_DECLS
> +
> +#define TYPE_DISPLAY_CHANNEL display_channel_get_type()
> +
> +#define DISPLAY_CHANNEL(obj) \
> + (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_DISPLAY_CHANNEL,
> DisplayChannel))
> +#define DISPLAY_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_DISPLAY_CHANNEL,
> DisplayChannelClass))
> +#define IS_DISPLAY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),
> TYPE_DISPLAY_CHANNEL))
> +#define IS_DISPLAY_CHANNEL_CLASS(klass)
> (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_DISPLAY_CHANNEL))
> +#define DISPLAY_CHANNEL_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_DISPLAY_CHANNEL,
> DisplayChannelClass))
> +
> +typedef struct DisplayChannel DisplayChannel;
> +typedef struct DisplayChannelClass DisplayChannelClass;
> +typedef struct DisplayChannelPrivate DisplayChannelPrivate;
> +
> +struct DisplayChannel
> +{
> + CommonGraphicsChannel parent;
> +
> + DisplayChannelPrivate *priv;
> +};
> +
> +struct DisplayChannelClass
> +{
> + CommonGraphicsChannelClass parent_class;
> +};
> +
> +GType display_channel_get_type(void) G_GNUC_CONST;
>
> typedef struct DependItem {
> Drawable *drawable;
> @@ -154,69 +182,8 @@ struct _Drawable {
> } u;
> };
>
> -typedef struct DisplayChannelPrivate DisplayChannelPrivate;
> -/* FIXME: move to separate file */
> -struct DisplayChannelPrivate
> -{
> - DisplayChannel *pub;
> -
> - uint32_t bits_unique;
> -
> - MonitorsConfig *monitors_config;
> -
> - uint32_t renderer;
> - int enable_jpeg;
> - int enable_zlib_glz_wrap;
> -
> - Ring current_list; // of TreeItem
> - uint32_t current_size;
> -
> - uint32_t drawable_count;
> - _Drawable drawables[NUM_DRAWABLES];
> - _Drawable *free_drawables;
> -
> - int stream_video;
> - GArray *video_codecs;
> - uint32_t stream_count;
> - Stream streams_buf[NUM_STREAMS];
> - Stream *free_streams;
> - Ring streams;
> - ItemTrace items_trace[NUM_TRACE_ITEMS];
> - uint32_t next_item_trace;
> - uint64_t streams_size_total;
> -
> - RedSurface surfaces[NUM_SURFACES];
> - uint32_t n_surfaces;
> - SpiceImageSurfaces image_surfaces;
> -
> - ImageCache image_cache;
> -
> - int gl_draw_async_count;
> -
> -/* TODO: some day unify this, make it more runtime.. */
> - stat_info_t add_stat;
> - stat_info_t exclude_stat;
> - stat_info_t __exclude_stat;
> -#ifdef RED_WORKER_STAT
> - uint32_t add_count;
> - uint32_t add_with_shadow_count;
> -#endif
> -#ifdef RED_STATISTICS
> - uint64_t *cache_hits_counter;
> - uint64_t *add_to_cache_counter;
> - uint64_t *non_cache_counter;
> -#endif
> - ImageEncoderSharedData encoder_shared_data;
> -};
> -
> -struct DisplayChannel {
> - CommonGraphicsChannel common; // Must be the first thing
> -
> - DisplayChannelPrivate priv[1];
> -};
> -
> #define FOREACH_DCC(_channel, _iter, _data) \
> - GLIST_FOREACH((_channel ? RED_CHANNEL(_channel)->clients :
> NULL), \
> + GLIST_FOREACH((_channel ?
> red_channel_get_clients(RED_CHANNEL(_channel)) : NULL), \
> _iter, DisplayChannelClient, _data)
>
> int display_channel_get_stream_id(DisplayChannel *display, Stream
> *stream);
> @@ -262,8 +229,9 @@
> void display_channel_set_stream_video
> (DisplayCha
>
> int stream_video);
> void display_channel_set_video_codecs
> (DisplayChannel *display,
>
> GArray *video_codecs);
> +int display_channel_get_stream_video
> (DisplayChannel *display);
> int display_channel_get_streams_timeout
> (DisplayChannel *display);
> -void display_channel_compress_stats_print
> (const DisplayChannel *display);
> +void display_channel_compress_stats_print
> (DisplayChannel *display);
> void display_channel_compress_stats_reset
> (DisplayChannel *display);
> void display_channel_surface_unref
> (DisplayChannel *display,
>
> uint32_t surface_id);
> @@ -415,4 +383,6 @@ static inline void region_add_clip_rects(QRegion
> *rgn, SpiceClipRects *data)
> }
> }
>
> +G_END_DECLS
> +
> #endif /* DISPLAY_CHANNEL_H_ */
> diff --git a/server/dummy-channel-client.c b/server/dummy-channel-
> client.c
> index 1b72137..b7fee6f 100644
> --- a/server/dummy-channel-client.c
> +++ b/server/dummy-channel-client.c
> @@ -37,9 +37,11 @@ struct DummyChannelClientPrivate
>
> static int dummy_channel_client_pre_create_validate(RedChannel
> *channel, RedClient *client)
> {
> - if (red_client_get_channel(client, channel->type, channel->id))
> {
> + uint32_t type, id;
> + g_object_get(channel, "channel-type", &type, "id", &id, NULL);
> + if (red_client_get_channel(client, type, id)) {
> spice_printerr("Error client %p: duplicate channel type %d
> id %d",
> - client, channel->type, channel->id);
> + client, type, id);
> return FALSE;
> }
> return TRUE;
> @@ -54,6 +56,9 @@ static gboolean
> dummy_channel_client_initable_init(GInitable *initable,
> RedChannelClient *rcc = RED_CHANNEL_CLIENT(self);
> RedClient *client = red_channel_client_get_client(rcc);
> RedChannel *channel = red_channel_client_get_channel(rcc);
> + uint32_t type, id;
> +
> + g_object_get(channel, "channel-type", &type, "id", &id, NULL);
> pthread_mutex_lock(&client->lock);
> if (!dummy_channel_client_pre_create_validate(channel,
> client)) {
> @@ -61,7 +66,7 @@ static gboolean
> dummy_channel_client_initable_init(GInitable *initable,
> SPICE_SERVER_ERROR,
> SPICE_SERVER_ERROR_FAILED,
> "Client %p: duplicate channel type %d id %d",
> - client, channel->type, channel->id);
> + client, type, id);
> goto cleanup;
> }
>
> @@ -94,10 +99,12 @@ static void
> dummy_channel_client_disconnect(RedChannelClient *rcc)
> DummyChannelClient *self = DUMMY_CHANNEL_CLIENT(rcc);
> RedChannel *channel = red_channel_client_get_channel(rcc);
> GList *link;
> + uint32_t type, id;
>
> - if (channel && (link = g_list_find(channel->clients, rcc))) {
> + if (channel && (link =
> g_list_find(red_channel_get_clients(channel), rcc))) {
> + g_object_get(channel, "channel-type", &type, "id", &id,
> NULL);
> spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc,
> channel,
> - channel->type, channel->id);
> + type, id);
> red_channel_remove_client(channel, link->data);
> }
> self->priv->connected = FALSE;
> diff --git a/server/dummy-channel.c b/server/dummy-channel.c
> new file mode 100644
> index 0000000..3b65bce
> --- /dev/null
> +++ b/server/dummy-channel.c
> @@ -0,0 +1,49 @@
> +/* dummy-channel.c */
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include "dummy-channel.h"
> +
> +G_DEFINE_TYPE(DummyChannel, dummy_channel, RED_TYPE_CHANNEL)
> +
> +static void
> +dummy_channel_class_init(DummyChannelClass *klass)
> +{
> +}
> +
> +static void
> +dummy_channel_init(DummyChannel *self)
> +{
> +}
> +
> +// TODO: red_worker can use this one
> +static void dummy_watch_update_mask(SpiceWatch *watch, int
> event_mask)
> +{
> +}
> +
> +static SpiceWatch *dummy_watch_add(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_dummym, no need
> for core. Can be NULL
> +static const SpiceCoreInterface dummy_core = {
> + .watch_update_mask = dummy_watch_update_mask,
> + .watch_add = dummy_watch_add,
> + .watch_remove = dummy_watch_remove,
> +};
> +
> +RedChannel *dummy_channel_new(RedsState *reds, uint32_t type,
> uint32_t id)
> +{
> + return g_object_new(TYPE_DUMMY_CHANNEL,
> + "spice-server", reds,
> + "core-interface", &dummy_core,
> + "channel-type", type,
> + "id", id,
> + NULL);
> +}
> diff --git a/server/dummy-channel.h b/server/dummy-channel.h
> new file mode 100644
> index 0000000..9527633
> --- /dev/null
> +++ b/server/dummy-channel.h
> @@ -0,0 +1,60 @@
> +/*
> + Copyright (C) 2009-2015 Red Hat, Inc.
> +
> + This library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later
> version.
> +
> + This library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with this library; if not, see <http://www.gnu.org/
> licenses/>.
> + */
> +
> +#ifndef __DUMMY_CHANNEL_H__
> +#define __DUMMY_CHANNEL_H__
> +
> +#include <glib-object.h>
> +
> +#include "red-channel.h"
> +
> +G_BEGIN_DECLS
> +
> +// TODO: tmp, for channels that don't use RedChannel yet (e.g., snd
> channel), but
> +// do use the client callbacks. So the channel clients are not
> connected (the channel doesn't
> +// have list of them, but they do have a link to the channel, and
> the client has a list of them)
> +
> +#define TYPE_DUMMY_CHANNEL dummy_channel_get_type()
> +
> +#define DUMMY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),
> TYPE_DUMMY_CHANNEL, DummyChannel))
> +#define DUMMY_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_DUMMY_CHANNEL,
> DummyChannelClass))
> +#define _IS_DUMMY_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),
> TYPE_DUMMY_CHANNEL))
> +#define _IS_DUMMY_CHANNEL_CLASS(klass)
> (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_DUMMY_CHANNEL))
> +#define DUMMY_CHANNEL_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_DUMMY_CHANNEL,
> DummyChannelClass))
> +
> +typedef struct DummyChannel DummyChannel;
> +typedef struct DummyChannelClass DummyChannelClass;
> +
> +struct DummyChannel
> +{
> + RedChannel parent;
> +};
> +
> +struct DummyChannelClass
> +{
> + RedChannelClass parent_class;
> +};
> +
> +GType dummy_channel_get_type(void) G_GNUC_CONST;
> +
> +RedChannel *dummy_channel_new(RedsState *reds, uint32_t type,
> uint32_t id);
> +
> +G_END_DECLS
> +
> +#endif /* __DUMMY_CHANNEL_H__ */
> diff --git a/server/inputs-channel.c b/server/inputs-channel.c
> index d0f534a..aadcf4b 100644
> --- a/server/inputs-channel.c
> +++ b/server/inputs-channel.c
> @@ -57,6 +57,27 @@
> #define RECEIVE_BUF_SIZE \
> (4096 + (REDS_AGENT_WINDOW_SIZE +
> REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
>
> +struct InputsChannel
> +{
> + RedChannel parent;
> +
> + uint8_t recv_buf[RECEIVE_BUF_SIZE];
> + VDAgentMouseState mouse_state;
> + int src_during_migrate;
> + SpiceTimer *key_modifiers_timer;
> +
> + SpiceKbdInstance *keyboard;
> + SpiceMouseInstance *mouse;
> + SpiceTabletInstance *tablet;
> +};
> +
> +struct InputsChannelClass
> +{
> + RedChannelClass parent_class;
> +};
> +
> +G_DEFINE_TYPE(InputsChannel, inputs_channel, RED_TYPE_CHANNEL)
> +
> struct SpiceKbdState {
> uint8_t push_ext_type;
>
> @@ -105,18 +126,6 @@ RedsState*
> spice_tablet_state_get_server(SpiceTabletState *st)
> return st->reds;
> }
>
> -struct InputsChannel {
> - RedChannel base;
> - uint8_t recv_buf[RECEIVE_BUF_SIZE];
> - VDAgentMouseState mouse_state;
> - int src_during_migrate;
> - SpiceTimer *key_modifiers_timer;
> -
> - SpiceKbdInstance *keyboard;
> - SpiceMouseInstance *mouse;
> - SpiceTabletInstance *tablet;
> -};
> -
> typedef struct RedKeyModifiersPipeItem {
> RedPipeItem base;
> uint8_t modifiers;
> @@ -275,7 +284,7 @@ static int
> inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
> InputsChannel *inputs_channel =
> INPUTS_CHANNEL(red_channel_client_get_channel(rcc));
> InputsChannelClient *icc = INPUTS_CHANNEL_CLIENT(rcc);
> uint32_t i;
> - RedsState *reds = red_channel_get_server(&inputs_channel->base);
> + RedsState *reds =
> red_channel_get_server(RED_CHANNEL(inputs_channel));
>
> switch (type) {
> case SPICE_MSGC_INPUTS_KEY_DOWN: {
> @@ -359,12 +368,15 @@ static int
> inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
> reds_handle_agent_mouse_event(reds, &inputs_channel-
> >mouse_state);
> } else if (inputs_channel_get_tablet(inputs_channel)) {
> SpiceTabletInterface *sif;
> - sif =
> SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)-
> >base.sif, SpiceTabletInterface, base);
> - sif-
> >wheel(inputs_channel_get_tablet(inputs_channel), dz,
> RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state));
> + sif =
> SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)-
> >base.sif,
> + SpiceTabletInterface, base);
> + sif-
> >wheel(inputs_channel_get_tablet(inputs_channel), dz,
> + RED_MOUSE_STATE_TO_LOCAL(mouse_press-
> >buttons_state));
> }
> } else if (inputs_channel_get_mouse(inputs_channel)) {
> SpiceMouseInterface *sif;
> - sif =
> SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif,
> SpiceMouseInterface, base);
> + sif =
> SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif,
> + SpiceMouseInterface, base);
> sif->motion(inputs_channel_get_mouse(inputs_channel), 0,
> 0, dz,
> RED_MOUSE_STATE_TO_LOCAL(mouse_press-
> >buttons_state));
> }
> @@ -379,12 +391,15 @@ static int
> inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
> reds_handle_agent_mouse_event(reds, &inputs_channel-
> >mouse_state);
> } else if (inputs_channel_get_tablet(inputs_channel)) {
> SpiceTabletInterface *sif;
> - sif =
> SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)-
> >base.sif, SpiceTabletInterface, base);
> - sif-
> >buttons(inputs_channel_get_tablet(inputs_channel),
> RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state));
> + sif =
> SPICE_CONTAINEROF(inputs_channel_get_tablet(inputs_channel)-
> >base.sif,
> + SpiceTabletInterface, base);
> + sif-
> >buttons(inputs_channel_get_tablet(inputs_channel),
> + RED_MOUSE_STATE_TO_LOCAL(mouse_release-
> >buttons_state));
> }
> } else if (inputs_channel_get_mouse(inputs_channel)) {
> SpiceMouseInterface *sif;
> - sif =
> SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif,
> SpiceMouseInterface, base);
> + sif =
> SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif,
> + SpiceMouseInterface, base);
> sif->buttons(inputs_channel_get_mouse(inputs_channel),
> RED_MOUSE_STATE_TO_LOCAL(mouse_release-
> >buttons_state));
> }
> @@ -519,11 +534,11 @@ static void inputs_migrate(RedChannelClient
> *rcc)
>
> static void inputs_channel_push_keyboard_modifiers(InputsChannel
> *inputs, uint8_t modifiers)
> {
> - if (!inputs || !red_channel_is_connected(&inputs->base) ||
> + if (!inputs || !red_channel_is_connected(RED_CHANNEL(inputs)) ||
> inputs->src_during_migrate) {
> return;
> }
> - red_channel_pipes_new_add_push(&inputs->base,
> + red_channel_pipes_new_add_push(RED_CHANNEL(inputs),
> red_inputs_key_modifiers_item_new, (void*)&modifiers);
> }
>
> @@ -569,44 +584,65 @@ static int
> inputs_channel_handle_migrate_data(RedChannelClient *rcc,
>
> InputsChannel* inputs_channel_new(RedsState *reds)
> {
> - ChannelCbs channel_cbs = { NULL, };
> + return g_object_new(TYPE_INPUTS_CHANNEL,
> + "spice-server", reds,
> + "core-interface",
> reds_get_core_interface(reds),
> + "channel-type", (int)SPICE_CHANNEL_INPUTS,
> + "id", 0,
> + "handle-acks", FALSE,
> + "migration-flags",
> + (guint)(SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER),
> + NULL);
> +
> +}
> +
> +static void
> +inputs_channel_constructed(GObject *object)
> +{
> ClientCbs client_cbs = { NULL, };
> - InputsChannel *inputs;
> -
> - channel_cbs.config_socket = inputs_channel_config_socket;
> - channel_cbs.on_disconnect = inputs_channel_on_disconnect;
> - channel_cbs.send_item = inputs_channel_send_item;
> - channel_cbs.alloc_recv_buf = inputs_channel_alloc_msg_rcv_buf;
> - channel_cbs.release_recv_buf =
> inputs_channel_release_msg_rcv_buf;
> - channel_cbs.handle_migrate_data =
> inputs_channel_handle_migrate_data;
> - channel_cbs.handle_migrate_flush_mark =
> inputs_channel_handle_migrate_flush_mark;
> -
> - inputs = INPUTS_CHANNEL(red_channel_create_parser(
> - sizeof(InputsChannel),
> - reds,
> - reds_get_core_interface(reds),
> - SPICE_CHANNEL_INPUTS, 0,
> - FALSE, /* handle_acks */
> - spice_get_client_channel_parser(
> SPICE_CHANNEL_INPUTS, NULL),
> - inputs_channel_handle_parsed,
> - &channel_cbs,
> - SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER));
> -
> - if (!inputs) {
> - spice_error("failed to allocate Inputs Channel");
> - }
> + InputsChannel *self = INPUTS_CHANNEL(object);
> + RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
> +
> + G_OBJECT_CLASS(inputs_channel_parent_class)-
> >constructed(object);
>
> client_cbs.connect = inputs_connect;
> client_cbs.migrate = inputs_migrate;
> - red_channel_register_client_cbs(&inputs->base, &client_cbs,
> NULL);
> + red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs,
> NULL);
>
> - red_channel_set_cap(&inputs->base,
> SPICE_INPUTS_CAP_KEY_SCANCODE);
> - reds_register_channel(reds, &inputs->base);
> + red_channel_set_cap(RED_CHANNEL(self),
> SPICE_INPUTS_CAP_KEY_SCANCODE);
> + reds_register_channel(reds, RED_CHANNEL(self));
>
> - if (!(inputs->key_modifiers_timer = reds_core_timer_add(reds,
> key_modifiers_sender, inputs))) {
> + self->key_modifiers_timer = reds_core_timer_add(reds,
> key_modifiers_sender, self);
> + if (!self->key_modifiers_timer) {
> spice_error("key modifiers timer create failed");
> }
> - return inputs;
> +}
> +
> +static void
> +inputs_channel_init(InputsChannel *self)
> +{
> +}
> +
> +
> +static void
> +inputs_channel_class_init(InputsChannelClass *klass)
> +{
> + GObjectClass *object_class = G_OBJECT_CLASS(klass);
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + object_class->constructed = inputs_channel_constructed;
> +
> + channel_class->parser =
> spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL);
> + channel_class->handle_parsed = inputs_channel_handle_parsed;
> +
> + /* channel callbacks */
> + channel_class->config_socket = inputs_channel_config_socket;
> + channel_class->on_disconnect = inputs_channel_on_disconnect;
> + channel_class->send_item = inputs_channel_send_item;
> + channel_class->alloc_recv_buf =
> inputs_channel_alloc_msg_rcv_buf;
> + channel_class->release_recv_buf =
> inputs_channel_release_msg_rcv_buf;
> + channel_class->handle_migrate_data =
> inputs_channel_handle_migrate_data;
> + channel_class->handle_migrate_flush_mark =
> inputs_channel_handle_migrate_flush_mark;
> }
>
> static SpiceKbdInstance* inputs_channel_get_keyboard(InputsChannel
> *inputs)
> @@ -621,7 +657,7 @@ int inputs_channel_set_keyboard(InputsChannel
> *inputs, SpiceKbdInstance *keyboar
> return -1;
> }
> inputs->keyboard = keyboard;
> - inputs->keyboard->st =
> spice_kbd_state_new(red_channel_get_server(&inputs->base));
> + inputs->keyboard->st =
> spice_kbd_state_new(red_channel_get_server(RED_CHANNEL(inputs)));
> return 0;
> }
>
> diff --git a/server/inputs-channel.h b/server/inputs-channel.h
> index ae84eed..26569fa 100644
> --- a/server/inputs-channel.h
> +++ b/server/inputs-channel.h
> @@ -22,15 +22,30 @@
> // This include should only be used by reds.c and inputs-channel.c
>
> #include <stdint.h>
> +#include <glib-object.h>
> #include <spice/vd_agent.h>
>
> #include "red-channel.h"
>
> -#define INPUTS_CHANNEL(channel) ((InputsChannel*)(channel))
> +G_BEGIN_DECLS
> +
> +#define TYPE_INPUTS_CHANNEL inputs_channel_get_type()
> +
> +#define INPUTS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),
> TYPE_INPUTS_CHANNEL, InputsChannel))
> +#define INPUTS_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_INPUTS_CHANNEL,
> InputsChannelClass))
> +#define INPUTS_IS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),
> TYPE_INPUTS_CHANNEL))
> +#define INPUTS_IS_CHANNEL_CLASS(klass)
> (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_INPUTS_CHANNEL))
> +#define INPUTS_CHANNEL_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_INPUTS_CHANNEL,
> InputsChannelClass))
>
> typedef struct InputsChannel InputsChannel;
> +typedef struct InputsChannelClass InputsChannelClass;
> +
> +GType inputs_channel_get_type(void) G_GNUC_CONST;
>
> InputsChannel* inputs_channel_new(RedsState *reds);
> +
> const VDAgentMouseState
> *inputs_channel_get_mouse_state(InputsChannel *inputs);
> void inputs_channel_on_keyboard_leds_change(InputsChannel *inputs,
> uint8_t leds);
> void inputs_channel_set_tablet_logical_size(InputsChannel *inputs,
> int x_res, int y_res);
> @@ -44,4 +59,6 @@ RedsState*
> spice_tablet_state_get_server(SpiceTabletState *dev);
> RedsState* spice_kbd_state_get_server(SpiceKbdState *dev);
> gboolean inputs_channel_is_src_during_migrate(InputsChannel
> *inputs);
>
> +G_END_DECLS
> +
> #endif
> diff --git a/server/main-channel-client.c b/server/main-channel-
> client.c
> index b47b1e0..daa3dfc 100644
> --- a/server/main-channel-client.c
> +++ b/server/main-channel-client.c
> @@ -435,7 +435,7 @@ void
> main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
> spice_printerr("client %p connected: %d seamless %d", client,
> success, seamless);
> if (mcc->priv->mig_wait_connect) {
> RedChannel *channel =
> red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
> - MainChannel *main_channel = SPICE_CONTAINEROF(channel,
> MainChannel, base);
> + MainChannel *main_channel = MAIN_CHANNEL(channel);
>
> mcc->priv->mig_wait_connect = FALSE;
> mcc->priv->mig_connect_ok = success;
> @@ -453,7 +453,7 @@ void
> main_channel_client_handle_migrate_dst_do_seamless(MainChannelClient
> *mcc,
> uint32_t
> src_version)
> {
> RedChannel *channel =
> red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
> - if (reds_on_migrate_dst_set_seamless(channel->reds, mcc,
> src_version)) {
> + if
> (reds_on_migrate_dst_set_seamless(red_channel_get_server(channel),
> mcc, src_version)) {
> mcc->priv->seamless_mig_dst = TRUE;
> red_channel_client_pipe_add_empty_msg(RED_CHANNEL_CLIENT(mcc
> ),
> SPICE_MSG_MAIN_MIGRATE_
> DST_SEAMLESS_ACK);
> @@ -553,7 +553,7 @@ void
> main_channel_client_migrate_dst_complete(MainChannelClient *mcc)
> if (mcc->priv->mig_wait_prev_complete) {
> if (mcc->priv->mig_wait_prev_try_seamless) {
> RedChannel *channel =
> red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc));
> - spice_assert(g_list_length(channel->clients) == 1);
> + spice_assert(red_channel_get_n_clients(channel) == 1);
> red_channel_client_pipe_add_type(RED_CHANNEL_CLIENT(mcc)
> ,
> RED_PIPE_ITEM_TYPE_MAIN
> _MIGRATE_BEGIN_SEAMLESS);
> } else {
> @@ -609,9 +609,11 @@ static void do_ping_client(MainChannelClient
> *mcc,
> if (has_interval && interval > 0) {
> mcc->priv->ping_interval = interval * MSEC_PER_SEC;
> }
> - reds_core_timer_start(channel->reds, mcc->priv->ping_timer,
> mcc->priv->ping_interval);
> + reds_core_timer_start(red_channel_get_server(channel),
> + mcc->priv->ping_timer, mcc->priv-
> >ping_interval);
> } else if (!strcmp(opt, "off")) {
> - reds_core_timer_cancel(channel->reds, mcc->priv-
> >ping_timer);
> + reds_core_timer_cancel(red_channel_get_server(channel),
> + mcc->priv->ping_timer);
> } else {
> return;
> }
> @@ -624,11 +626,13 @@ static void ping_timer_cb(void *opaque)
>
> if (!red_channel_client_is_connected(RED_CHANNEL_CLIENT(mcc))) {
> spice_printerr("not connected to peer, ping off");
> - reds_core_timer_cancel(channel->reds, mcc->priv-
> >ping_timer);
> + reds_core_timer_cancel(red_channel_get_server(channel),
> + mcc->priv->ping_timer);
> return;
> }
> do_ping_client(mcc, NULL, 0, 0);
> - reds_core_timer_start(channel->reds, mcc->priv->ping_timer, mcc-
> >priv->ping_interval);
> + reds_core_timer_start(red_channel_get_server(channel),
> + mcc->priv->ping_timer, mcc->priv-
> >ping_interval);
> }
> #endif /* RED_STATISTICS */
>
> @@ -693,7 +697,8 @@ uint64_t
> main_channel_client_get_roundtrip_ms(MainChannelClient *mcc)
> void main_channel_client_migrate(RedChannelClient *rcc)
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> - reds_on_main_channel_migrate(channel->reds,
> MAIN_CHANNEL_CLIENT(rcc));
> + reds_on_main_channel_migrate(red_channel_get_server(channel),
> + MAIN_CHANNEL_CLIENT(rcc));
> red_channel_client_default_migrate(rcc);
> }
>
> @@ -754,7 +759,7 @@ static void
> main_channel_marshall_channels(RedChannelClient *rcc,
> RedChannel *channel = red_channel_client_get_channel(rcc);
>
> red_channel_client_init_send_data(rcc,
> SPICE_MSG_MAIN_CHANNELS_LIST, item);
> - channels_info = reds_msg_channels_new(channel->reds);
> + channels_info =
> reds_msg_channels_new(red_channel_get_server(channel));
> spice_marshall_msg_main_channels_list(m, channels_info);
> free(channels_info);
> }
> @@ -829,7 +834,8 @@ static void
> main_channel_marshall_migrate_data_item(RedChannelClient *rcc,
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA,
> item);
> - reds_marshall_migrate_data(channel->reds, m); // TODO: from reds
> split. ugly separation.
> + // TODO: from reds split. ugly separation.
> + reds_marshall_migrate_data(red_channel_get_server(channel), m);
> }
>
> static void main_channel_marshall_init(RedChannelClient *rcc,
> @@ -847,7 +853,7 @@ static void
> main_channel_marshall_init(RedChannelClient *rcc,
> if (item->is_client_mouse_allowed) {
> init.supported_mouse_modes |= SPICE_MOUSE_MODE_CLIENT;
> }
> - init.agent_connected = reds_has_vdagent(channel->reds);
> + init.agent_connected =
> reds_has_vdagent(red_channel_get_server(channel));
> init.agent_tokens = REDS_AGENT_WINDOW_SIZE;
> init.multi_media_time = item->multi_media_time;
> init.ram_hint = item->ram_hint;
> @@ -891,11 +897,9 @@ static void
> main_channel_marshall_migrate_begin(SpiceMarshaller *m, RedChannelCl
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> SpiceMsgMainMigrationBegin migrate;
> - MainChannel *main_ch;
>
> red_channel_client_init_send_data(rcc,
> SPICE_MSG_MAIN_MIGRATE_BEGIN, item);
> - main_ch = SPICE_CONTAINEROF(channel, MainChannel, base);
> - main_channel_fill_migrate_dst_info(main_ch, &migrate.dst_info);
> + main_channel_fill_migrate_dst_info(MAIN_CHANNEL(channel),
> &migrate.dst_info);
> spice_marshall_msg_main_migrate_begin(m, &migrate);
> }
>
> @@ -905,11 +909,9 @@ static void
> main_channel_marshall_migrate_begin_seamless(SpiceMarshaller *m,
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> SpiceMsgMainMigrateBeginSeamless migrate_seamless;
> - MainChannel *main_ch;
>
> red_channel_client_init_send_data(rcc,
> SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS, item);
> - main_ch = SPICE_CONTAINEROF(channel, MainChannel, base);
> - main_channel_fill_migrate_dst_info(main_ch,
> &migrate_seamless.dst_info);
> + main_channel_fill_migrate_dst_info(MAIN_CHANNEL(channel),
> &migrate_seamless.dst_info);
> migrate_seamless.src_mig_version =
> SPICE_MIGRATION_PROTOCOL_VERSION;
> spice_marshall_msg_main_migrate_begin_seamless(m,
> &migrate_seamless);
> }
> @@ -935,7 +937,7 @@ static void
> main_channel_marshall_migrate_switch(SpiceMarshaller *m, RedChannelC
>
> spice_printerr("");
> red_channel_client_init_send_data(rcc,
> SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST, item);
> - main_ch = SPICE_CONTAINEROF(channel, MainChannel, base);
> + main_ch = MAIN_CHANNEL(channel);
> mig_target = main_channel_get_migration_target(main_ch);
> migrate.port = mig_target->port;
> migrate.sport = mig_target->sport;
> diff --git a/server/main-channel.c b/server/main-channel.c
> index e69e34e..cf5ee6a 100644
> --- a/server/main-channel.c
> +++ b/server/main-channel.c
> @@ -27,9 +27,30 @@
> #include "main-channel.h"
> #include "main-channel-client.h"
>
> +// approximate max receive message size for main channel
> +#define MAIN_CHANNEL_RECEIVE_BUF_SIZE \
> + (4096 + (REDS_AGENT_WINDOW_SIZE +
> REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
> +
> +struct MainChannel
> +{
> + RedChannel parent;
> +
> + uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE];
> + // TODO: add refs and release (afrer all clients completed
> migration in one way or the other?)
> + RedsMigSpice mig_target;
> + int num_clients_mig_wait;
> +};
> +
> +struct MainChannelClass
> +{
> + RedChannelClass parent_class;
> +};
> +
> +G_DEFINE_TYPE(MainChannel, main_channel, RED_TYPE_CHANNEL)
> +
> int main_channel_is_connected(MainChannel *main_chan)
> {
> - return red_channel_is_connected(&main_chan->base);
> + return red_channel_is_connected(RED_CHANNEL(main_chan));
> }
>
> /*
> @@ -76,27 +97,29 @@ void main_channel_push_mouse_mode(MainChannel
> *main_chan, int current_mode,
> .is_client_mouse_allowed=is_client_mouse_allowed,
> };
>
> - red_channel_pipes_new_add_push(&main_chan->base,
> + red_channel_pipes_new_add_push(RED_CHANNEL(main_chan),
> main_mouse_mode_item_new, &info);
> }
>
> void main_channel_push_agent_connected(MainChannel *main_chan)
> {
> - if (red_channel_test_remote_cap(&main_chan->base,
> SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) {
> - red_channel_pipes_add_type(&main_chan->base,
> RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS);
> + if (red_channel_test_remote_cap(RED_CHANNEL(main_chan),
> + SPICE_MAIN_CAP_AGENT_CONNECTED_T
> OKENS)) {
> + red_channel_pipes_add_type(RED_CHANNEL(main_chan),
> + RED_PIPE_ITEM_TYPE_MAIN_AGENT_CON
> NECTED_TOKENS);
> } else {
> - red_channel_pipes_add_empty_msg(&main_chan->base,
> SPICE_MSG_MAIN_AGENT_CONNECTED);
> + red_channel_pipes_add_empty_msg(RED_CHANNEL(main_chan),
> SPICE_MSG_MAIN_AGENT_CONNECTED);
> }
> }
>
> void main_channel_push_agent_disconnected(MainChannel *main_chan)
> {
> - red_channel_pipes_add_type(&main_chan->base,
> RED_PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED);
> + red_channel_pipes_add_type(RED_CHANNEL(main_chan),
> RED_PIPE_ITEM_TYPE_MAIN_AGENT_DISCONNECTED);
> }
>
> static void main_channel_push_migrate_data_item(MainChannel
> *main_chan)
> {
> - red_channel_pipes_add_type(&main_chan->base,
> RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA);
> + red_channel_pipes_add_type(RED_CHANNEL(main_chan),
> RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_DATA);
> }
>
> static int main_channel_handle_migrate_data(RedChannelClient *rcc,
> @@ -107,7 +130,7 @@ static int
> main_channel_handle_migrate_data(RedChannelClient *rcc,
> SpiceMigrateDataHeader *header = (SpiceMigrateDataHeader
> *)message;
>
> /* not supported with multi-clients */
> - spice_assert(g_list_length(channel->clients) == 1);
> + spice_assert(red_channel_get_n_clients(channel) == 1);
>
> if (size < sizeof(SpiceMigrateDataHeader) +
> sizeof(SpiceMigrateDataMain)) {
> spice_printerr("bad message size %u", size);
> @@ -119,7 +142,9 @@ static int
> main_channel_handle_migrate_data(RedChannelClient *rcc,
> spice_error("bad header");
> return FALSE;
> }
> - return reds_handle_migrate_data(channel->reds, mcc,
> (SpiceMigrateDataMain *)(header + 1), size);
> + return reds_handle_migrate_data(red_channel_get_server(channel),
> mcc,
> + (SpiceMigrateDataMain *)(header
> + 1),
> + size);
> }
>
> void main_channel_push_multi_media_time(MainChannel *main_chan, int
> time)
> @@ -128,7 +153,7 @@ void
> main_channel_push_multi_media_time(MainChannel *main_chan, int time)
> .time = time,
> };
>
> - red_channel_pipes_new_add_push(&main_chan->base,
> + red_channel_pipes_new_add_push(RED_CHANNEL(main_chan),
> main_multi_media_time_item_new, &info);
> }
>
> @@ -150,15 +175,16 @@ static void
> main_channel_fill_mig_target(MainChannel *main_channel, RedsMigSpice
> void main_channel_migrate_switch(MainChannel *main_chan,
> RedsMigSpice *mig_target)
> {
> main_channel_fill_mig_target(main_chan, mig_target);
> - red_channel_pipes_add_type(&main_chan->base,
> RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST);
> + red_channel_pipes_add_type(RED_CHANNEL(main_chan),
> RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST);
> }
>
> static int main_channel_handle_parsed(RedChannelClient *rcc,
> uint32_t size, uint16_t type,
> void *message)
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> - MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel,
> base);
> + MainChannel *main_chan = MAIN_CHANNEL(channel);
> MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
> + RedsState *reds = red_channel_get_server(channel);
>
> switch (type) {
> case SPICE_MSGC_MAIN_AGENT_START: {
> @@ -169,18 +195,18 @@ static int
> main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
> return FALSE;
> }
> tokens = (SpiceMsgcMainAgentStart *)message;
> - reds_on_main_agent_start(channel->reds, mcc, tokens-
> >num_tokens);
> + reds_on_main_agent_start(reds, mcc, tokens->num_tokens);
> break;
> }
> case SPICE_MSGC_MAIN_AGENT_DATA: {
> - reds_on_main_agent_data(channel->reds, mcc, message, size);
> + reds_on_main_agent_data(reds, mcc, message, size);
> break;
> }
> case SPICE_MSGC_MAIN_AGENT_TOKEN: {
> SpiceMsgcMainAgentTokens *tokens;
>
> tokens = (SpiceMsgcMainAgentTokens *)message;
> - reds_on_main_agent_tokens(channel->reds, mcc, tokens-
> >num_tokens);
> + reds_on_main_agent_tokens(reds, mcc, tokens->num_tokens);
> break;
> }
> case SPICE_MSGC_MAIN_ATTACH_CHANNELS:
> @@ -204,7 +230,7 @@ static int
> main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
> ((SpiceMsgcMainMigrateDstDoSeamless *)message)-
> >src_version);
> break;
> case SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST:
> - reds_on_main_mouse_mode_request(channel->reds, message,
> size);
> + reds_on_main_mouse_mode_request(reds, message, size);
> break;
> case SPICE_MSGC_PONG: {
> main_channel_client_handle_pong(mcc, (SpiceMsgPing
> *)message, size);
> @@ -226,11 +252,11 @@ static uint8_t
> *main_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
> uint32_t size)
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> - MainChannel *main_chan = SPICE_CONTAINEROF(channel, MainChannel,
> base);
> + MainChannel *main_chan = MAIN_CHANNEL(channel);
> MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
>
> if (type == SPICE_MSGC_MAIN_AGENT_DATA) {
> - return reds_get_agent_data_buffer(channel->reds, mcc, size);
> + return
> reds_get_agent_data_buffer(red_channel_get_server(channel), mcc,
> size);
> } else {
> return main_chan->recv_buf;
> }
> @@ -243,7 +269,7 @@ static void
> main_channel_release_msg_rcv_buf(RedChannelClient *rcc,
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> if (type == SPICE_MSGC_MAIN_AGENT_DATA) {
> - reds_release_agent_data_buffer(channel->reds, msg);
> + reds_release_agent_data_buffer(red_channel_get_server(channe
> l), msg);
> }
> }
>
> @@ -256,8 +282,7 @@ static int
> main_channel_handle_migrate_flush_mark(RedChannelClient *rcc)
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> spice_debug(NULL);
> - main_channel_push_migrate_data_item(SPICE_CONTAINEROF(channel,
> - MainChannel, base));
> + main_channel_push_migrate_data_item(MAIN_CHANNEL(channel));
> return TRUE;
> }
>
> @@ -282,12 +307,14 @@ MainChannelClient
> *main_channel_link(MainChannel *channel, RedClient *client,
>
> int main_channel_getsockname(MainChannel *main_chan, struct sockaddr
> *sa, socklen_t *salen)
> {
> - return main_chan ?
> getsockname(red_channel_get_first_socket(&main_chan->base), sa,
> salen) : -1;
> + return main_chan ?
> + getsockname(red_channel_get_first_socket(RED_CHANNEL(main_ch
> an)), sa, salen) : -1;
> }
>
> int main_channel_getpeername(MainChannel *main_chan, struct sockaddr
> *sa, socklen_t *salen)
> {
> - return main_chan ?
> getpeername(red_channel_get_first_socket(&main_chan->base), sa,
> salen) : -1;
> + return main_chan ?
> + getpeername(red_channel_get_first_socket(RED_CHANNEL(main_ch
> an)), sa, salen) : -1;
> }
>
> // TODO: ? shouldn't it disonnect all clients? or shutdown all
> main_channels?
> @@ -295,42 +322,64 @@ void main_channel_close(MainChannel *main_chan)
> {
> int socketfd;
>
> - if (main_chan && (socketfd =
> red_channel_get_first_socket(&main_chan->base)) != -1) {
> + if (main_chan && (socketfd =
> red_channel_get_first_socket(RED_CHANNEL(main_chan))) != -1) {
> close(socketfd);
> }
> }
>
> MainChannel* main_channel_new(RedsState *reds)
> {
> - RedChannel *channel;
> - ChannelCbs channel_cbs = { NULL, };
> - ClientCbs client_cbs = {NULL, };
> + // TODO: set the migration flag of the channel
> + return g_object_new(TYPE_MAIN_CHANNEL,
> + "spice-server", reds,
> + "core-interface",
> reds_get_core_interface(reds),
> + "channel-type", (gint)SPICE_CHANNEL_MAIN,
> + "id", 0,
> + "handle-acks", FALSE, /* handle_acks */
> + "migration-flags",
> + (SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER),
> + NULL);
> +}
> +
> +static void
> +main_channel_constructed(GObject *object)
> +{
> + MainChannel *self = MAIN_CHANNEL(object);
> + ClientCbs client_cbs = { NULL, };
>
> - channel_cbs.config_socket = main_channel_config_socket;
> - channel_cbs.on_disconnect = main_channel_client_on_disconnect;
> - channel_cbs.send_item = main_channel_client_send_item;
> - channel_cbs.alloc_recv_buf = main_channel_alloc_msg_rcv_buf;
> - channel_cbs.release_recv_buf = main_channel_release_msg_rcv_buf;
> - channel_cbs.handle_migrate_flush_mark =
> main_channel_handle_migrate_flush_mark;
> - channel_cbs.handle_migrate_data =
> main_channel_handle_migrate_data;
> + G_OBJECT_CLASS(main_channel_parent_class)->constructed(object);
>
> - // TODO: set the migration flag of the channel
> - channel = red_channel_create_parser(sizeof(MainChannel), reds,
> - reds_get_core_interface(reds
> ),
> - SPICE_CHANNEL_MAIN, 0,
> - FALSE, /* handle_acks */
> - spice_get_client_channel_par
> ser(SPICE_CHANNEL_MAIN, NULL),
> - main_channel_handle_parsed,
> - &channel_cbs,
> - SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER);
> - spice_assert(channel);
> - red_channel_set_cap(channel,
> SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
> - red_channel_set_cap(channel, SPICE_MAIN_CAP_SEAMLESS_MIGRATE);
> + red_channel_set_cap(RED_CHANNEL(self),
> SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
> + red_channel_set_cap(RED_CHANNEL(self),
> SPICE_MAIN_CAP_SEAMLESS_MIGRATE);
>
> client_cbs.migrate = main_channel_client_migrate;
> - red_channel_register_client_cbs(channel, &client_cbs, NULL);
> + red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs,
> NULL);
> +}
>
> - return MAIN_CHANNEL(channel);
> +static void
> +main_channel_init(MainChannel *self)
> +{
> +}
> +
> +static void
> +main_channel_class_init(MainChannelClass *klass)
> +{
> + GObjectClass *object_class = G_OBJECT_CLASS(klass);
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + object_class->constructed = main_channel_constructed;
> +
> + channel_class->parser =
> spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL);
> + channel_class->handle_parsed = main_channel_handle_parsed;
> +
> + /* channel callbacks */
> + channel_class->config_socket = main_channel_config_socket;
> + channel_class->on_disconnect =
> main_channel_client_on_disconnect;
> + channel_class->send_item = main_channel_client_send_item;
> + channel_class->alloc_recv_buf = main_channel_alloc_msg_rcv_buf;
> + channel_class->release_recv_buf =
> main_channel_release_msg_rcv_buf;
> + channel_class->handle_migrate_flush_mark =
> main_channel_handle_migrate_flush_mark;
> + channel_class->handle_migrate_data =
> main_channel_handle_migrate_data;
> }
>
> static int main_channel_connect_semi_seamless(MainChannel
> *main_channel)
> @@ -351,7 +400,7 @@ static int
> main_channel_connect_seamless(MainChannel *main_channel)
> GListIter iter;
> RedChannelClient *rcc;
>
> - spice_assert(g_list_length(main_channel->base.clients) == 1);
> + spice_assert(red_channel_get_n_clients(RED_CHANNEL(main_channel)
> ) == 1);
>
> FOREACH_CLIENT(main_channel, iter, rcc) {
> MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
> @@ -375,8 +424,10 @@ int main_channel_migrate_connect(MainChannel
> *main_channel, RedsMigSpice *mig_ta
> return main_channel_connect_semi_seamless(main_channel);
> } else {
> RedChannelClient *rcc;
> + GList *clients =
> red_channel_get_clients(RED_CHANNEL(main_channel));
>
> - rcc = g_list_nth_data(main_channel->base.clients, 0);
> + /* just test the first one */
> + rcc = g_list_nth_data(clients, 0);
>
> if (!red_channel_client_test_remote_cap(rcc,
> SPICE_MAIN_CAP_SEAML
> ESS_MIGRATE)) {
> @@ -408,7 +459,7 @@ int main_channel_migrate_src_complete(MainChannel
> *main_chan, int success)
>
> spice_printerr("");
>
> - if (!main_chan->base.clients) {
> + if (!red_channel_get_clients(RED_CHANNEL(main_chan))) {
> spice_printerr("no peer connected");
> return 0;
> }
> diff --git a/server/main-channel.h b/server/main-channel.h
> index 6e89f14..19beb7c 100644
> --- a/server/main-channel.h
> +++ b/server/main-channel.h
> @@ -19,22 +19,34 @@
> #define __MAIN_CHANNEL_H__
>
> #include <stdint.h>
> +#include <glib-object.h>
> #include <spice/vd_agent.h>
> #include <common/marshaller.h>
>
> #include "red-channel.h"
>
> -#define MAIN_CHANNEL(channel) ((MainChannel*)(channel))
> +G_BEGIN_DECLS
> +
> +#define TYPE_MAIN_CHANNEL main_channel_get_type()
> +
> +#define MAIN_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),
> TYPE_MAIN_CHANNEL, MainChannel))
> +#define MAIN_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_MAIN_CHANNEL,
> MainChannelClass))
> +#define IS_MAIN_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),
> TYPE_MAIN_CHANNEL))
> +#define IS_MAIN_CHANNEL_CLASS(klass)
> (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_MAIN_CHANNEL))
> +#define MAIN_CHANNEL_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_MAIN_CHANNEL,
> MainChannelClass))
> +
> +typedef struct MainChannel MainChannel;
> +typedef struct MainChannelClass MainChannelClass;
> +
> +GType main_channel_get_type(void) G_GNUC_CONST;
>
> // TODO: Defines used to calculate receive buffer size, and also by
> reds.c
> // other options: is to make a reds_main_consts.h, to duplicate
> defines.
> #define REDS_AGENT_WINDOW_SIZE 10
> #define REDS_NUM_INTERNAL_AGENT_MESSAGES 1
>
> -// approximate max receive message size for main channel
> -#define MAIN_CHANNEL_RECEIVE_BUF_SIZE \
> - (4096 + (REDS_AGENT_WINDOW_SIZE +
> REDS_NUM_INTERNAL_AGENT_MESSAGES) * SPICE_AGENT_MAX_DATA_SIZE)
> -
> struct RedsMigSpice {
> char *host;
> char *cert_subject;
> @@ -43,14 +55,6 @@ struct RedsMigSpice {
> };
> typedef struct RedsMigSpice RedsMigSpice;
>
> -typedef struct MainChannel {
> - RedChannel base;
> - uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE];
> - RedsMigSpice mig_target; // TODO: add refs and release (afrer
> all clients completed migration in one way or the other?)
> - int num_clients_mig_wait;
> -} MainChannel;
> -
> -
> MainChannel *main_channel_new(RedsState *reds);
> RedClient *main_channel_get_client_by_link_id(MainChannel
> *main_chan, uint32_t link_id);
> /* This is a 'clone' from the reds.h Channel.link callback to allow
> passing link_id */
> @@ -83,4 +87,6 @@ int main_channel_migrate_src_complete(MainChannel
> *main_chan, int success);
> void main_channel_on_migrate_connected(MainChannel *main_channel,
> gboolean success, gboolean
> seamless);
>
> +G_END_DECLS
> +
> #endif
> diff --git a/server/red-channel-client-private.h b/server/red-
> channel-client-private.h
> index 83fef23..e77cdf9 100644
> --- a/server/red-channel-client-private.h
> +++ b/server/red-channel-client-private.h
> @@ -21,6 +21,25 @@
> #include "red-channel.h"
> #include "red-channel-client.h"
>
> +typedef struct RedChannelClientLatencyMonitor {
> + int state;
> + uint64_t last_pong_time;
> + SpiceTimer *timer;
> + uint32_t id;
> + int tcp_nodelay;
> + int warmup_was_sent;
> +
> + int64_t roundtrip;
> +} RedChannelClientLatencyMonitor;
> +
> +typedef struct RedChannelClientConnectivityMonitor {
> + int state;
> + uint32_t out_bytes;
> + uint32_t in_bytes;
> + uint32_t timeout;
> + SpiceTimer *timer;
> +} RedChannelClientConnectivityMonitor;
> +
> typedef struct OutgoingHandler {
> OutgoingHandlerInterface *cb;
> void *opaque;
> diff --git a/server/red-channel-client.c b/server/red-channel-
> client.c
> index 9426b13..c562e8e 100644
> --- a/server/red-channel-client.c
> +++ b/server/red-channel-client.c
> @@ -93,6 +93,8 @@ typedef struct MarkerPipeItem {
>
> static void red_channel_client_start_ping_timer(RedChannelClient
> *rcc, uint32_t timeout)
> {
> + SpiceCoreInterfaceInternal *core;
> +
> if (!rcc->priv->latency_monitor.timer) {
> return;
> }
> @@ -100,11 +102,15 @@ static void
> red_channel_client_start_ping_timer(RedChannelClient *rcc, uint32_t
> return;
> }
> rcc->priv->latency_monitor.state = PING_STATE_TIMER;
> - rcc->priv->channel->core->timer_start(rcc->priv-
> >latency_monitor.timer, timeout);
> +
> + core = red_channel_get_core_interface(rcc->priv->channel);
> + core->timer_start(rcc->priv->latency_monitor.timer, timeout);
> }
>
> static void red_channel_client_cancel_ping_timer(RedChannelClient
> *rcc)
> {
> + SpiceCoreInterfaceInternal *core;
> +
> if (!rcc->priv->latency_monitor.timer) {
> return;
> }
> @@ -112,7 +118,8 @@ static void
> red_channel_client_cancel_ping_timer(RedChannelClient *rcc)
> return;
> }
>
> - rcc->priv->channel->core->timer_cancel(rcc->priv-
> >latency_monitor.timer);
> + core = red_channel_get_core_interface(rcc->priv->channel);
> + core->timer_cancel(rcc->priv->latency_monitor.timer);
> rcc->priv->latency_monitor.state = PING_STATE_NONE;
> }
>
> @@ -187,10 +194,10 @@ red_channel_client_set_property(GObject
> *object,
> break;
> case PROP_CHANNEL:
> if (self->priv->channel)
> - red_channel_unref(self->priv->channel);
> + g_object_unref(self->priv->channel);
> self->priv->channel = g_value_get_pointer(value);
> if (self->priv->channel)
> - red_channel_ref(self->priv->channel);
> + g_object_ref(self->priv->channel);
> break;
> case PROP_CLIENT:
> self->priv->client = g_value_get_pointer(value);
> @@ -243,7 +250,7 @@ red_channel_client_finalize(GObject *object)
>
> red_channel_client_destroy_remote_caps(self);
> if (self->priv->channel) {
> - red_channel_unref(self->priv->channel);
> + g_object_unref(self->priv->channel);
> }
>
> G_OBJECT_CLASS(red_channel_client_parent_class)-
> >finalize(object);
> @@ -361,7 +368,6 @@ void red_channel_client_on_output(void *opaque,
> int n)
> if (rcc->priv->connectivity_monitor.timer) {
> rcc->priv->connectivity_monitor.out_bytes += n;
> }
> - stat_inc_counter(reds, rcc->priv->channel->out_bytes_counter,
> n);
> }
>
> void red_channel_client_on_input(void *opaque, int n)
> @@ -391,12 +397,14 @@ void red_channel_client_prepare_out_msg(void
> *opaque, struct iovec *vec,
>
> void red_channel_client_on_out_block(void *opaque)
> {
> + SpiceCoreInterfaceInternal *core;
> RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
>
> rcc->priv->send_data.blocked = TRUE;
> - rcc->priv->channel->core->watch_update_mask(rcc->priv->stream-
> >watch,
> - SPICE_WATCH_EVENT_RE
> AD |
> - SPICE_WATCH_EVENT_WR
> ITE);
> + core = red_channel_get_core_interface(rcc->priv->channel);
> + core->watch_update_mask(rcc->priv->stream->watch,
> + SPICE_WATCH_EVENT_READ |
> + SPICE_WATCH_EVENT_WRITE);
> }
>
> static inline int
> red_channel_client_urgent_marshaller_is_active(RedChannelClient *rcc)
> @@ -439,9 +447,9 @@ static void
> red_channel_client_send_migrate(RedChannelClient *rcc)
> SpiceMsgMigrate migrate;
>
> red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE, NULL);
> - migrate.flags = rcc->priv->channel->migration_flags;
> + g_object_get(rcc->priv->channel, "migration-flags",
> &migrate.flags, NULL);
> spice_marshall_msg_migrate(rcc->priv->send_data.marshaller,
> &migrate);
> - if (rcc->priv->channel->migration_flags &
> SPICE_MIGRATE_NEED_FLUSH) {
> + if (migrate.flags & SPICE_MIGRATE_NEED_FLUSH) {
> rcc->priv->wait_migrate_flush_mark = TRUE;
> }
>
> @@ -515,7 +523,7 @@ static void
> red_channel_client_send_item(RedChannelClient *rcc, RedPipeItem *ite
> case RED_PIPE_ITEM_TYPE_MARKER:
> break;
> default:
> - rcc->priv->channel->channel_cbs.send_item(rcc, item);
> + red_channel_send_item(rcc->priv->channel, rcc, item);
> break;
> }
> red_pipe_item_unref(item);
> @@ -558,9 +566,10 @@ void red_channel_client_on_out_msg_done(void
> *opaque)
>
> red_channel_client_release_sent_item(rcc);
> if (rcc->priv->send_data.blocked) {
> + SpiceCoreInterfaceInternal *core =
> red_channel_get_core_interface(rcc->priv->channel);
> rcc->priv->send_data.blocked = FALSE;
> - rcc->priv->channel->core->watch_update_mask(rcc->priv-
> >stream->watch,
> - SPICE_WATCH_EVEN
> T_READ);
> + core->watch_update_mask(rcc->priv->stream->watch,
> + SPICE_WATCH_EVENT_READ);
> }
>
> if (red_channel_client_urgent_marshaller_is_active(rcc)) {
> @@ -645,8 +654,13 @@ static void red_channel_client_ping_timer(void
> *opaque)
>
> static inline int
> red_channel_client_waiting_for_ack(RedChannelClient *rcc)
> {
> - return (rcc->priv->channel->handle_acks &&
> - (rcc->priv->ack_data.messages_window > rcc->priv-
> >ack_data.client_window * 2));
> + gboolean handle_acks;
> + g_object_get(rcc->priv->channel,
> + "handle-acks", &handle_acks,
> + NULL);
> +
> + return (handle_acks && (rcc->priv->ack_data.messages_window >
> + rcc->priv->ack_data.client_window * 2));
> }
>
> /*
> @@ -687,6 +701,7 @@ static void
> red_channel_client_connectivity_timer(void *opaque)
> }
>
> if (is_alive) {
> + SpiceCoreInterfaceInternal *core =
> red_channel_get_core_interface(rcc->priv->channel);
> monitor->in_bytes = 0;
> monitor->out_bytes = 0;
> if (rcc->priv->send_data.blocked ||
> red_channel_client_waiting_for_ack(rcc)) {
> @@ -697,18 +712,24 @@ static void
> red_channel_client_connectivity_timer(void *opaque)
> } else {
> monitor->state = CONNECTIVITY_STATE_CONNECTED;
> }
> - rcc->priv->channel->core->timer_start(rcc->priv-
> >connectivity_monitor.timer,
> + core->timer_start(rcc->priv->connectivity_monitor.timer,
> rcc->priv-
> >connectivity_monitor.timeout);
> } else {
> + uint32_t type, id;
> + g_object_get(rcc->priv->channel,
> + "channel-type", &type,
> + "id", &id,
> + NULL);
> monitor->state = CONNECTIVITY_STATE_DISCONNECTED;
> spice_warning("rcc %p on channel %d:%d has been unresponsive
> for more than %u ms, disconnecting",
> - rcc, rcc->priv->channel->type, rcc->priv-
> >channel->id, monitor->timeout);
> + rcc, type, id, monitor->timeout);
> red_channel_client_disconnect(rcc);
> }
> }
>
> void
> red_channel_client_start_connectivity_monitoring(RedChannelClient
> *rcc, uint32_t timeout_ms)
> {
> + SpiceCoreInterfaceInternal *core =
> red_channel_get_core_interface(rcc->priv->channel);
> if (!red_channel_client_is_connected(rcc)) {
> return;
> }
> @@ -721,8 +742,8 @@ void
> red_channel_client_start_connectivity_monitoring(RedChannelClient
> *rcc, uin
> * on this channel.
> */
> if (rcc->priv->latency_monitor.timer == NULL) {
> - rcc->priv->latency_monitor.timer = rcc->priv->channel->core-
> >timer_add(
> - rcc->priv->channel->core, red_channel_client_ping_timer,
> rcc);
> + rcc->priv->latency_monitor.timer = core->timer_add(
> + core, red_channel_client_ping_timer, rcc);
> if (!red_client_during_migrate_at_target(rcc->priv->client))
> {
> red_channel_client_start_ping_timer(rcc,
> PING_TEST_IDLE_NET_TIMEOUT_MS);
> }
> @@ -730,12 +751,12 @@ void
> red_channel_client_start_connectivity_monitoring(RedChannelClient
> *rcc, uin
> }
> if (rcc->priv->connectivity_monitor.timer == NULL) {
> rcc->priv->connectivity_monitor.state =
> CONNECTIVITY_STATE_CONNECTED;
> - rcc->priv->connectivity_monitor.timer = rcc->priv->channel-
> >core->timer_add(
> - rcc->priv->channel->core,
> red_channel_client_connectivity_timer, rcc);
> + rcc->priv->connectivity_monitor.timer = core->timer_add(
> + core, red_channel_client_connectivity_timer, rcc);
> rcc->priv->connectivity_monitor.timeout = timeout_ms;
> if (!red_client_during_migrate_at_target(rcc->priv->client))
> {
> - rcc->priv->channel->core->timer_start(rcc->priv-
> >connectivity_monitor.timer,
> - rcc->priv-
> >connectivity_monitor.timeout);
> + core->timer_start(rcc->priv->connectivity_monitor.timer,
> + rcc->priv-
> >connectivity_monitor.timeout);
> }
> }
> }
> @@ -832,9 +853,11 @@ static const SpiceDataHeaderOpaque
> mini_header_wrapper = {NULL, sizeof(SpiceMini
>
> static int red_channel_client_pre_create_validate(RedChannel
> *channel, RedClient *client)
> {
> - if (red_client_get_channel(client, channel->type, channel->id))
> {
> + uint32_t type, id;
> + g_object_get(channel, "channel-type", &type, "id", &id, NULL);
> + if (red_client_get_channel(client, type, id)) {
> spice_printerr("Error client %p: duplicate channel type %d
> id %d",
> - client, channel->type, channel->id);
> + client, type, id);
> return FALSE;
> }
> return TRUE;
> @@ -845,24 +868,28 @@ static gboolean
> red_channel_client_initable_init(GInitable *initable,
> GError **error)
> {
> GError *local_error = NULL;
> + SpiceCoreInterfaceInternal *core;
> RedChannelClient *self = RED_CHANNEL_CLIENT(initable);
> pthread_mutex_lock(&self->priv->client->lock);
> if (!red_channel_client_pre_create_validate(self->priv->channel,
> self->priv->client)) {
> + uint32_t id, type;
> + g_object_get(self->priv->channel,
> + "channel-type", &type,
> + "id", &id,
> + NULL);
> g_set_error(&local_error,
> SPICE_SERVER_ERROR,
> SPICE_SERVER_ERROR_FAILED,
> "Client %p: duplicate channel type %d id %d",
> - self->priv->client, self->priv->channel->type,
> - self->priv->channel->id);
> + self->priv->client, type, id);
> goto cleanup;
> }
>
> + core = red_channel_get_core_interface(self->priv->channel);
> if (self->priv->monitor_latency
> && reds_stream_get_family(self->priv->stream) != AF_UNIX) {
> self->priv->latency_monitor.timer =
> - self->priv->channel->core->timer_add(self->priv-
> >channel->core,
> - red_channel_client_
> ping_timer,
> - self);
> + core->timer_add(core, red_channel_client_ping_timer,
> self);
>
> if (!self->priv->client->during_target_migrate) {
> red_channel_client_start_ping_timer(self,
> @@ -872,27 +899,26 @@ static gboolean
> red_channel_client_initable_init(GInitable *initable,
> }
>
> self->incoming.opaque = self;
> - self->incoming.cb = &self->priv->channel->incoming_cb;
> + self->incoming.cb = red_channel_get_incoming_handler(self->priv-
> >channel);
> self->incoming.header.data = self->incoming.header_buf;
>
> self->priv->outgoing.opaque = self;
> - self->priv->outgoing.cb = &self->priv->channel->outgoing_cb;
> + self->priv->outgoing.cb = red_channel_get_outgoing_handler(self-
> >priv->channel);
> self->priv->outgoing.pos = 0;
> self->priv->outgoing.size = 0;
>
> g_queue_init(&self->priv->pipe);
> if (self->priv->stream)
> self->priv->stream->watch =
> - self->priv->channel->core->watch_add(self->priv-
> >channel->core,
> - self->priv->stream-
> >socket,
> - SPICE_WATCH_EVENT_R
> EAD,
> - red_channel_client_
> event,
> - self);
> - self->priv->id = g_list_length(self->priv->channel->clients);
> + core->watch_add(core, self->priv->stream->socket,
> + SPICE_WATCH_EVENT_READ,
> + red_channel_client_event,
> + self);
> + self->priv->id = red_channel_get_n_clients(self->priv->channel);
> red_channel_add_client(self->priv->channel, self);
> red_client_add_channel(self->priv->client, self);
>
> - if (!self->priv->channel->channel_cbs.config_socket(self)) {
> + if (!red_channel_config_socket(self->priv->channel, self)) {
> g_set_error_literal(&local_error,
> SPICE_SERVER_ERROR,
> SPICE_SERVER_ERROR_FAILED,
> @@ -953,8 +979,9 @@ static void
> red_channel_client_seamless_migration_done(RedChannelClient *rcc)
> red_channel_client_start_ping_timer(rcc,
> PING_TEST_IDLE_NET_TIMEOUT_MS);
> }
> if (rcc->priv->connectivity_monitor.timer) {
> - rcc->priv->channel->core->timer_start(rcc->priv-
> >connectivity_monitor.timer,
> - rcc->priv-
> >connectivity_monitor.timeout);
> + SpiceCoreInterfaceInternal *core =
> red_channel_get_core_interface(rcc->priv->channel);
> + core->timer_start(rcc->priv->connectivity_monitor.timer,
> + rcc->priv-
> >connectivity_monitor.timeout);
> }
> }
> }
> @@ -973,13 +1000,14 @@ int
> red_channel_client_is_waiting_for_migrate_data(RedChannelClient *rcc)
>
> void red_channel_client_default_migrate(RedChannelClient *rcc)
> {
> + SpiceCoreInterfaceInternal *core =
> red_channel_get_core_interface(rcc->priv->channel);
> if (rcc->priv->latency_monitor.timer) {
> red_channel_client_cancel_ping_timer(rcc);
> - rcc->priv->channel->core->timer_remove(rcc->priv-
> >latency_monitor.timer);
> + core->timer_remove(rcc->priv->latency_monitor.timer);
> rcc->priv->latency_monitor.timer = NULL;
> }
> if (rcc->priv->connectivity_monitor.timer) {
> - rcc->priv->channel->core->timer_remove(rcc->priv-
> >connectivity_monitor.timer);
> + core->timer_remove(rcc->priv->connectivity_monitor.timer);
> rcc->priv->connectivity_monitor.timer = NULL;
> }
> red_channel_client_pipe_add_type(rcc,
> RED_PIPE_ITEM_TYPE_MIGRATE);
> @@ -996,7 +1024,8 @@ void red_channel_client_destroy(RedChannelClient
> *rcc)
> void red_channel_client_shutdown(RedChannelClient *rcc)
> {
> if (rcc->priv->stream && !rcc->priv->stream->shutdown) {
> - rcc->priv->channel->core->watch_remove(rcc->priv->stream-
> >watch);
> + SpiceCoreInterfaceInternal *core =
> red_channel_get_core_interface(rcc->priv->channel);
> + core->watch_remove(rcc->priv->stream->watch);
> rcc->priv->stream->watch = NULL;
> shutdown(rcc->priv->stream->socket, SHUT_RDWR);
> rcc->priv->stream->shutdown = TRUE;
> @@ -1227,8 +1256,10 @@ void red_channel_client_push(RedChannelClient
> *rcc)
> }
> if (red_channel_client_no_item_being_sent(rcc) &&
> g_queue_is_empty(&rcc->priv->pipe)
> && rcc->priv->stream->watch) {
> - rcc->priv->channel->core->watch_update_mask(rcc->priv-
> >stream->watch,
> - SPICE_WATCH_EVEN
> T_READ);
> + SpiceCoreInterfaceInternal *core;
> + core = red_channel_get_core_interface(rcc->priv->channel);
> + core->watch_update_mask(rcc->priv->stream->watch,
> + SPICE_WATCH_EVENT_READ);
> }
> rcc->priv->during_send = FALSE;
> g_object_unref(rcc);
> @@ -1302,8 +1333,9 @@ static void
> red_channel_client_handle_pong(RedChannelClient *rcc, SpiceMsgPing *
> static void
> red_channel_client_handle_migrate_flush_mark(RedChannelClient *rcc)
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> - if (channel->channel_cbs.handle_migrate_flush_mark) {
> - channel->channel_cbs.handle_migrate_flush_mark(rcc);
> + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
> + if (klass->handle_migrate_flush_mark) {
> + klass->handle_migrate_flush_mark(rcc);
> }
> }
>
> @@ -1319,20 +1351,24 @@ static void
> red_channel_client_handle_migrate_data(RedChannelClient *rcc,
> void *message)
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
> + uint32_t type, id;
> +
> + g_object_get(channel, "channel-type", &type, "id", &id, NULL);
> spice_debug("channel type %d id %d rcc %p size %u",
> - channel->type, channel->id, rcc, size);
> - if (!channel->channel_cbs.handle_migrate_data) {
> + type, id, rcc, size);
> + if (!klass->handle_migrate_data) {
> return;
> }
> if (!red_channel_client_is_waiting_for_migrate_data(rcc)) {
> spice_channel_client_error(rcc, "unexpected");
> return;
> }
> - if (channel->channel_cbs.handle_migrate_data_get_serial) {
> + if (klass->handle_migrate_data_get_serial) {
> red_channel_client_set_message_serial(rcc,
> - channel->channel_cbs.handle_migrate_data_get_serial(rcc,
> size, message));
> + klass->handle_migrate_data_get_serial(rcc, size,
> message));
> }
> - if (!channel->channel_cbs.handle_migrate_data(rcc, size,
> message)) {
> + if (!klass->handle_migrate_data(rcc, size, message)) {
> spice_channel_client_error(rcc, "handle_migrate_data
> failed");
> return;
> }
> @@ -1448,9 +1484,10 @@ static inline gboolean
> prepare_pipe_add(RedChannelClient *rcc, RedPipeItem *item
> return FALSE;
> }
> if (g_queue_is_empty(&rcc->priv->pipe) && rcc->priv->stream-
> >watch) {
> - rcc->priv->channel->core->watch_update_mask(rcc->priv-
> >stream->watch,
> - SPICE_WATCH_EVEN
> T_READ |
> - SPICE_WATCH_EVEN
> T_WRITE);
> + SpiceCoreInterfaceInternal *core;
> + core = red_channel_get_core_interface(rcc->priv->channel);
> + core->watch_update_mask(rcc->priv->stream->watch,
> + SPICE_WATCH_EVENT_READ |
> SPICE_WATCH_EVENT_WRITE);
> }
> return TRUE;
> }
> @@ -1562,7 +1599,7 @@ gboolean
> red_channel_client_is_mini_header(RedChannelClient *rcc)
> static gboolean
> red_channel_client_default_is_connected(RedChannelClient *rcc)
> {
> return rcc->priv->channel
> - && (g_list_find(rcc->priv->channel->clients, rcc) != NULL);
> + && (g_list_find(red_channel_get_clients(rcc->priv->channel),
> rcc) != NULL);
> }
>
> gboolean red_channel_client_is_connected(RedChannelClient *rcc)
> @@ -1613,27 +1650,30 @@ void
> red_channel_client_push_set_ack(RedChannelClient *rcc)
> static void red_channel_client_default_disconnect(RedChannelClient
> *rcc)
> {
> RedChannel *channel = rcc->priv->channel;
> + SpiceCoreInterfaceInternal *core =
> red_channel_get_core_interface(channel);
> + uint32_t type, id;
>
> if (!red_channel_client_is_connected(rcc)) {
> return;
> }
> + g_object_get(channel, "channel-type", &type, "id", &id, NULL);
> spice_printerr("rcc=%p (channel=%p type=%d id=%d)", rcc,
> channel,
> - channel->type, channel->id);
> + type, id);
> red_channel_client_pipe_clear(rcc);
> if (rcc->priv->stream->watch) {
> - channel->core->watch_remove(rcc->priv->stream->watch);
> + core->watch_remove(rcc->priv->stream->watch);
> rcc->priv->stream->watch = NULL;
> }
> if (rcc->priv->latency_monitor.timer) {
> - channel->core->timer_remove(rcc->priv-
> >latency_monitor.timer);
> + core->timer_remove(rcc->priv->latency_monitor.timer);
> rcc->priv->latency_monitor.timer = NULL;
> }
> if (rcc->priv->connectivity_monitor.timer) {
> - channel->core->timer_remove(rcc->priv-
> >connectivity_monitor.timer);
> + core->timer_remove(rcc->priv->connectivity_monitor.timer);
> rcc->priv->connectivity_monitor.timer = NULL;
> }
> red_channel_remove_client(channel, rcc);
> - channel->channel_cbs.on_disconnect(rcc);
> + red_channel_on_disconnect(channel, rcc);
> }
>
> void red_channel_client_disconnect(RedChannelClient *rcc)
> @@ -1800,13 +1840,18 @@ void
> red_channel_client_pipe_remove_and_release_pos(RedChannelClient *rcc,
> gboolean red_channel_client_set_migration_seamless(RedChannelClient
> *rcc)
> {
> gboolean ret = FALSE;
> -
> - if (rcc->priv->channel->migration_flags &
> SPICE_MIGRATE_NEED_DATA_TRANSFER) {
> + uint32_t type, id, flags;
> +
> + g_object_get(rcc->priv->channel,
> + "channel-type", &type,
> + "id", &id,
> + "migration-flags", &flags,
> + NULL);
> + if (flags & SPICE_MIGRATE_NEED_DATA_TRANSFER) {
> rcc->priv->wait_migrate_data = TRUE;
> ret = TRUE;
> }
> - spice_debug("channel type %d id %d rcc %p wait data %d", rcc-
> >priv->channel->type,
> - rcc->priv->channel->id, rcc,
> + spice_debug("channel type %d id %d rcc %p wait data %d", type,
> id, rcc,
> rcc->priv->wait_migrate_data);
>
> return ret;
> diff --git a/server/red-channel-client.h b/server/red-channel-
> client.h
> index c2c6407..862d1c9 100644
> --- a/server/red-channel-client.h
> +++ b/server/red-channel-client.h
> @@ -62,8 +62,10 @@ GType red_channel_client_get_type(void)
> G_GNUC_CONST;
> #define spice_channel_client_error(rcc, format,
> ...) \
> do
> {
> \
> RedChannel *_ch =
> red_channel_client_get_channel(rcc); \
> + uint32_t _type,
> _id; \
> + g_object_get(_ch, "channel-type", &_type, "id", &_id,
> NULL); \
> spice_warning("rcc %p type %u id %u: " format,
> rcc, \
> - _ch->type, _ch->id, ##
> __VA_ARGS__); \
> + type, id, ##
> __VA_ARGS__); \
> red_channel_client_shutdown(rcc);
> \
> } while (0)
>
> diff --git a/server/red-channel.c b/server/red-channel.c
> index af49824..4281414 100644
> --- a/server/red-channel.c
> +++ b/server/red-channel.c
> @@ -69,9 +69,137 @@
> * 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)
> +{
> + 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)
> {
> - g_list_foreach(channel->clients,
> (GFunc)red_channel_client_receive, NULL);
> + 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 +207,158 @@ 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)
> +{
> + GParamSpec *spec;
> + 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;
> +
> + spec = 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_SPICE_SERVER,
> spec);
> +
> + spec = 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);
> + g_object_class_install_property(object_class,
> PROP_CORE_INTERFACE, spec);
> +
> + /* FIXME: generate enums for this in spice-common? */
> + spec = 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_TYPE, spec);
> +
> + spec = 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_ID, spec);
> +
> + spec = 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_HANDLE_ACKS,
> spec);
> +
> + spec = 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);
> + g_object_class_install_property(object_class,
> PROP_MIGRATION_FLAGS, spec);
> +}
> +
> +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_e
> rror;
> + 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_e
> rror;
> + 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 +413,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 +423,44 @@ 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_e
> rror;
> - 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_e
> rror;
> - 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_messa
> ge,
> - 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)
> +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 +477,13 @@ 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,15 @@ 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 +526,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 +538,13 @@ 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 +552,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 +578,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 +614,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 +643,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 +735,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 +764,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 +782,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 +982,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;
> }
> diff --git a/server/red-channel.h b/server/red-channel.h
> index 5299646..f95151c 100644
> --- a/server/red-channel.h
> +++ b/server/red-channel.h
> @@ -24,6 +24,7 @@
>
> #include <pthread.h>
> #include <limits.h>
> +#include <glib-object.h>
> #include <common/ring.h>
> #include <common/marshaller.h>
>
> @@ -34,6 +35,8 @@
> #include "stat.h"
> #include "red-pipe-item.h"
>
> +G_BEGIN_DECLS
> +
> typedef struct SpiceDataHeaderOpaque SpiceDataHeaderOpaque;
>
> typedef uint16_t (*get_msg_type_proc)(SpiceDataHeaderOpaque
> *header);
> @@ -125,23 +128,6 @@ typedef void
> (*channel_client_connect_proc)(RedChannel *channel, RedClient *clie
> typedef void (*channel_client_disconnect_proc)(RedChannelClient
> *base);
> typedef void (*channel_client_migrate_proc)(RedChannelClient *base);
>
> -// TODO: add ASSERTS for thread_id in client and channel calls
> -//
> -/*
> - * callbacks that are triggered from channel client stream events.
> - * They are called from the thread that listen to the stream events.
> - */
> -typedef struct {
> - channel_configure_socket_proc config_socket;
> - channel_disconnect_proc on_disconnect;
> - channel_send_pipe_item_proc send_item;
> - channel_alloc_msg_recv_buf_proc alloc_recv_buf;
> - channel_release_msg_recv_buf_proc release_recv_buf;
> - channel_handle_migrate_flush_mark_proc
> handle_migrate_flush_mark;
> - channel_handle_migrate_data_proc handle_migrate_data;
> - channel_handle_migrate_data_get_serial_proc
> handle_migrate_data_get_serial;
> -} ChannelCbs;
> -
>
> /*
> * callbacks that are triggered from client events.
> @@ -153,107 +139,84 @@ typedef struct {
> channel_client_migrate_proc migrate;
> } ClientCbs;
>
> -typedef struct RedChannelCapabilities {
> - int num_common_caps;
> - uint32_t *common_caps;
> - int num_caps;
> - uint32_t *caps;
> -} RedChannelCapabilities;
> -
> static inline gboolean test_capability(const uint32_t *caps, int
> num_caps, uint32_t cap)
> {
> return VD_AGENT_HAS_CAPABILITY(caps, num_caps, cap);
> }
>
> -typedef struct RedChannelClientLatencyMonitor {
> - int state;
> - uint64_t last_pong_time;
> - SpiceTimer *timer;
> - uint32_t id;
> - int tcp_nodelay;
> - int warmup_was_sent;
> +#define RED_TYPE_CHANNEL red_channel_get_type()
>
> - int64_t roundtrip;
> -} RedChannelClientLatencyMonitor;
> +#define RED_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),
> RED_TYPE_CHANNEL, RedChannel))
> +#define RED_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHANNEL,
> RedChannelClass))
> +#define RED_IS_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),
> RED_TYPE_CHANNEL))
> +#define RED_IS_CHANNEL_CLASS(klass)
> (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_CHANNEL))
> +#define RED_CHANNEL_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHANNEL,
> RedChannelClass))
>
> -typedef struct RedChannelClientConnectivityMonitor {
> - int state;
> - uint32_t out_bytes;
> - uint32_t in_bytes;
> - uint32_t timeout;
> - SpiceTimer *timer;
> -} RedChannelClientConnectivityMonitor;
> -
> -struct RedChannel {
> - uint32_t type;
> - uint32_t id;
> -
> - uint32_t refs;
> -
> - RingItem link; // channels link for reds
> -
> - const SpiceCoreInterfaceInternal *core;
> - int 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;
> +typedef struct RedChannel RedChannel;
> +typedef struct RedChannelClass RedChannelClass;
> +typedef struct RedChannelPrivate RedChannelPrivate;
>
> - OutgoingHandlerInterface outgoing_cb;
> - IncomingHandlerInterface incoming_cb;
> +struct RedChannel
> +{
> + GObject parent;
>
> - ChannelCbs channel_cbs;
> - ClientCbs client_cbs;
> + RedChannelPrivate *priv;
> +};
>
> - RedChannelCapabilities local_caps;
> - uint32_t migration_flags;
> +struct RedChannelClass
> +{
> + GObjectClass parent_class;
>
> - void *data;
> + /* subclasses must implement either handle_message(), or both
> parser() and
> + * handle_parsed() */
> + channel_handle_message_proc handle_message;
> + spice_parse_channel_func_t parser;
> + channel_handle_parsed_proc handle_parsed;
>
> - // 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
> + // TODO: add ASSERTS for thread_id in client and channel calls
> + /*
> + * callbacks that are triggered from channel client stream
> events.
> + * They are called from the thread that listen to the stream
> events.
> + */
> + channel_configure_socket_proc config_socket;
> + channel_disconnect_proc on_disconnect;
> + channel_send_pipe_item_proc send_item;
> + channel_alloc_msg_recv_buf_proc alloc_recv_buf;
> + channel_release_msg_recv_buf_proc release_recv_buf;
> + channel_handle_migrate_flush_mark_proc
> handle_migrate_flush_mark;
> + channel_handle_migrate_data_proc handle_migrate_data;
> + channel_handle_migrate_data_get_serial_proc
> handle_migrate_data_get_serial;
> };
>
> #define FOREACH_CLIENT(_channel, _iter, _data) \
> - GLIST_FOREACH((_channel ? RED_CHANNEL(_channel)->clients :
> NULL), \
> + GLIST_FOREACH((_channel ?
> red_channel_get_clients(RED_CHANNEL(_channel)) : NULL), \
> _iter, RedChannelClient, _data)
>
> -#define RED_CHANNEL(Channel) ((RedChannel *)(Channel))
> +/* Red Channel interface */
>
> -/* if one of the callbacks should cause disconnect, use
> red_channel_shutdown and don't
> - * explicitly destroy the channel */
> -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);
> +typedef struct RedChannelCapabilities {
> + int num_common_caps;
> + uint32_t *common_caps;
> + int num_caps;
> + uint32_t *caps;
> +} RedChannelCapabilities;
> +
> +GType red_channel_get_type(void) G_GNUC_CONST;
>
> /* alternative constructor, meant for marshaller based (inputs,main)
> channels,
> * will become default eventually */
> +/*
> RedChannel *red_channel_create_parser(int size,
> RedsState *reds,
> const
> SpiceCoreInterfaceInternal *core,
> uint32_t type, uint32_t id,
> - int handle_acks,
> + gboolean 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_ref(RedChannel *channel);
> -void red_channel_unref(RedChannel *channel);
> + */
> void red_channel_add_client(RedChannel *channel, RedChannelClient
> *rcc);
> void red_channel_remove_client(RedChannel *channel, RedChannelClient
> *rcc);
>
> @@ -264,11 +227,6 @@ void red_channel_register_client_cbs(RedChannel
> *channel, const ClientCbs *clien
> void red_channel_set_common_cap(RedChannel *channel, uint32_t cap);
> void red_channel_set_cap(RedChannel *channel, uint32_t cap);
>
> -// TODO: tmp, for channels that don't use RedChannel yet (e.g., snd
> channel), but
> -// do use the client callbacks. So the channel clients are not
> connected (the channel doesn't
> -// have list of them, but they do have a link to the channel, and
> the client has a list of them)
> -RedChannel *red_channel_create_dummy(int size, RedsState *reds,
> uint32_t type, uint32_t id);
> -
> int red_channel_is_connected(RedChannel *channel);
>
> /* seamless migration is supported for only one client. This routine
> @@ -332,6 +290,9 @@ void red_channel_receive(RedChannel *channel);
> void red_channel_send(RedChannel *channel);
> // For red_worker
> void red_channel_disconnect(RedChannel *channel);
> +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);
>
> /* return the sum of all the rcc pipe size */
> uint32_t red_channel_max_pipe_size(RedChannel *channel);
> @@ -344,8 +305,36 @@ uint32_t red_channel_sum_pipes_size(RedChannel
> *channel);
> typedef void (*channel_client_callback)(RedChannelClient *rcc);
> typedef void (*channel_client_callback_data)(RedChannelClient *rcc,
> void *data);
> void red_channel_apply_clients(RedChannel *channel,
> channel_client_callback v);
> -void red_channel_apply_clients_data(RedChannel *channel,
> channel_client_callback_data v, void * data);
> +void red_channel_apply_clients_data(RedChannel *channel,
> channel_client_callback_data v,
> + void *data);
> +GList *red_channel_get_clients(RedChannel *channel);
> +guint red_channel_get_n_clients(RedChannel *channel);
> struct RedsState* red_channel_get_server(RedChannel *channel);
> +SpiceCoreInterfaceInternal*
> red_channel_get_core_interface(RedChannel *channel);
> +
> +/* channel callback function */
> +int red_channel_config_socket(RedChannel *self, RedChannelClient
> *rcc);
> +void red_channel_on_disconnect(RedChannel *self, RedChannelClient
> *rcc);
> +void red_channel_send_item(RedChannel *self, RedChannelClient *rcc,
> RedPipeItem *item);
> +uint8_t* red_channel_alloc_recv_buf(RedChannel *self,
> RedChannelClient *rcc,
> + uint16_t type, uint32_t size);
> +void red_channel_release_recv_buf(RedChannel *self, RedChannelClient
> *rcc,
> + uint16_t type, uint32_t size,
> uint8_t *msg);
> +int red_channel_handle_migrate_flush_mark(RedChannel *self,
> RedChannelClient *rcc);
> +int red_channel_handle_migrate_data(RedChannel *self,
> RedChannelClient *rcc,
> + uint32_t size, void *message);
> +uint64_t red_channel_handle_migrate_data_get_serial(RedChannel
> *self,
> + RedChannelClient
> *rcc,
> + uint32_t size,
> void *message);
> +void red_channel_reset_thread_id(RedChannel *self);
> +StatNodeRef red_channel_get_stat_node(RedChannel *channel);
> +
> +/* FIXME: do these even need to be in RedChannel? It's really only
> used in
> + * RedChannelClient. Needs refactoring */
> +IncomingHandlerInterface*
> red_channel_get_incoming_handler(RedChannel *self);
> +OutgoingHandlerInterface*
> red_channel_get_outgoing_handler(RedChannel *self);
> +
> +RedChannelCapabilities*
> red_channel_get_local_capabilities(RedChannel *self);
>
> struct RedClient {
> RedsState *reds;
> @@ -419,4 +408,6 @@ int red_channel_wait_all_sent(RedChannel
> *channel,
>
> #define CHANNEL_BLOCKED_SLEEP_DURATION 10000 //micro
>
> +G_END_DECLS
> +
> #endif
> diff --git a/server/red-parse-qxl.h b/server/red-parse-qxl.h
> index 0da20ad..d5e7b6b 100644
> --- a/server/red-parse-qxl.h
> +++ b/server/red-parse-qxl.h
> @@ -65,6 +65,8 @@ static inline RedDrawable
> *red_drawable_ref(RedDrawable *drawable)
> return drawable;
> }
>
> +void red_drawable_unref(RedDrawable *red_drawable);
> +
> typedef struct RedUpdateCmd {
> QXLReleaseInfoExt release_info_ext;
> SpiceRect area;
> diff --git a/server/red-qxl.c b/server/red-qxl.c
> index 87d613b..68cab06 100644
> --- a/server/red-qxl.c
> +++ b/server/red-qxl.c
> @@ -82,7 +82,7 @@ static void red_qxl_set_display_peer(RedChannel
> *channel, RedClient *client,
> Dispatcher *dispatcher;
>
> spice_debug("%s", "");
> - dispatcher = (Dispatcher *)channel->data;
> + dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel),
> "dispatcher");
> payload.client = client;
> payload.stream = stream;
> payload.migration = migration;
> @@ -109,7 +109,7 @@ static void
> red_qxl_disconnect_display_peer(RedChannelClient *rcc)
> return;
> }
>
> - dispatcher = (Dispatcher *)channel->data;
> + dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel),
> "dispatcher");
>
> spice_printerr("");
> payload.rcc = rcc;
> @@ -126,11 +126,14 @@ static void
> red_qxl_display_migrate(RedChannelClient *rcc)
> RedWorkerMessageDisplayMigrate payload;
> Dispatcher *dispatcher;
> RedChannel *channel = red_channel_client_get_channel(rcc);
> + uint32_t type, id;
> +
> if (!channel) {
> return;
> }
> - dispatcher = (Dispatcher *)channel->data;
> - spice_printerr("channel type %u id %u", channel->type, channel-
> >id);
> + g_object_get(channel, "channel-type", &type, "id", &id, NULL);
> + dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel),
> "dispatcher");
> + spice_printerr("channel type %u id %u", type, id);
> payload.rcc = rcc;
> dispatcher_send_message(dispatcher,
> RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
> @@ -143,7 +146,7 @@ static void red_qxl_set_cursor_peer(RedChannel
> *channel, RedClient *client, Reds
> uint32_t *caps)
> {
> RedWorkerMessageCursorConnect payload = {0,};
> - Dispatcher *dispatcher = (Dispatcher *)channel->data;
> + Dispatcher *dispatcher = (Dispatcher
> *)g_object_get_data(G_OBJECT(channel), "dispatcher");
> spice_printerr("");
> payload.client = client;
> payload.stream = stream;
> @@ -171,7 +174,7 @@ static void
> red_qxl_disconnect_cursor_peer(RedChannelClient *rcc)
> return;
> }
>
> - dispatcher = (Dispatcher *)channel->data;
> + dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel),
> "dispatcher");
> spice_printerr("");
> payload.rcc = rcc;
>
> @@ -185,12 +188,14 @@ static void
> red_qxl_cursor_migrate(RedChannelClient *rcc)
> RedWorkerMessageCursorMigrate payload;
> Dispatcher *dispatcher;
> RedChannel *channel = red_channel_client_get_channel(rcc);
> + uint32_t type, id;
>
> if (!channel) {
> return;
> }
> - dispatcher = (Dispatcher *)channel->data;
> - spice_printerr("channel type %u id %u", channel->type, channel-
> >id);
> + g_object_get(channel, "channel-type", &type, "id", &id, NULL);
> + dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel),
> "dispatcher");
> + spice_printerr("channel type %u id %u", type, id);
> payload.rcc = rcc;
> dispatcher_send_message(dispatcher,
> RED_WORKER_MESSAGE_CURSOR_MIGRATE,
> diff --git a/server/red-replay-qxl.c b/server/red-replay-qxl.c
> index b5baded..78de48b 100644
> --- a/server/red-replay-qxl.c
> +++ b/server/red-replay-qxl.c
> @@ -24,7 +24,7 @@
> #include <zlib.h>
> #include <pthread.h>
> #include "reds.h"
> -#include "red-worker.h"
> +#include "red-qxl.h"
> #include "red-common.h"
> #include "memslot.h"
> #include "red-parse-qxl.h"
> diff --git a/server/red-worker.c b/server/red-worker.c
> index 40e58f2..f7f0726 100644
> --- a/server/red-worker.c
> +++ b/server/red-worker.c
> @@ -23,16 +23,12 @@
>
> #include <stdio.h>
> #include <stdarg.h>
> -#include <fcntl.h>
> -#include <sys/socket.h>
> -#include <netinet/in.h>
> #include <stdlib.h>
> #include <errno.h>
> #include <string.h>
> #include <unistd.h>
> #include <poll.h>
> #include <pthread.h>
> -#include <netinet/tcp.h>
> #include <openssl/ssl.h>
> #include <inttypes.h>
> #include <glib.h>
> @@ -93,8 +89,8 @@ struct RedWorker {
>
> static int display_is_connected(RedWorker *worker)
> {
> - return (worker->display_channel && red_channel_is_connected(
> - &worker->display_channel->common.base));
> + return worker->display_channel &&
> + red_channel_is_connected(RED_CHANNEL(worker-
> >display_channel));
> }
>
> void red_drawable_unref(RedDrawable *red_drawable)
> @@ -261,7 +257,7 @@ static int red_process_display(RedWorker *worker,
> int *ring_is_empty)
> spice_error("bad command type");
> }
> n++;
> - if (red_channel_all_blocked(&worker->display_channel-
> >common.base)
> + if (red_channel_all_blocked(RED_CHANNEL(worker-
> >display_channel))
> || spice_get_monotonic_time_ns() - start > NSEC_PER_SEC
> / 100) {
> worker->event_timeout = 0;
> return n;
> @@ -404,7 +400,7 @@ static void
> guest_set_client_capabilities(RedWorker *worker)
> return;
> }
> if ((worker->display_channel == NULL) ||
> - (RED_CHANNEL(worker->display_channel)->clients == NULL)) {
> + (red_channel_get_n_clients(RED_CHANNEL(worker-
> >display_channel)) == 0)) {
> red_qxl_set_client_capabilities(worker->qxl, FALSE, caps);
> } else {
> // Take least common denominator
> @@ -541,12 +537,12 @@ static void
> dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
> if (!worker->driver_cap_monitors_config) {
> red_worker_push_monitors_config(worker);
> }
> - red_pipes_add_verb(&worker->display_channel->common.base,
> + red_pipes_add_verb(RED_CHANNEL(worker->display_channel),
> SPICE_MSG_DISPLAY_MARK);
> - red_channel_push(&worker->display_channel->common.base);
> + red_channel_push(RED_CHANNEL(worker->display_channel));
> }
>
> - cursor_channel_init(worker->cursor_channel);
> + cursor_channel_do_init(worker->cursor_channel);
> }
>
> static void handle_dev_create_primary_surface(void *opaque, void
> *payload)
> @@ -665,7 +661,7 @@ static void handle_dev_oom(void *opaque, void
> *payload)
> RedWorker *worker = opaque;
> DisplayChannel *display = worker->display_channel;
>
> - RedChannel *display_red_channel = &display->common.base;
> + RedChannel *display_red_channel = RED_CHANNEL(display);
> int ring_is_empty;
>
> spice_return_if_fail(worker->running);
> @@ -1371,6 +1367,7 @@ RedWorker* red_worker_new(QXLInstance *qxl,
> channel = RED_CHANNEL(worker->cursor_channel);
> red_channel_set_stat_node(channel, stat_add_node(reds, worker-
> >stat, "cursor_channel", TRUE));
> red_channel_register_client_cbs(channel, client_cursor_cbs,
> dispatcher);
> + g_object_set_data(G_OBJECT(channel), "dispatcher", dispatcher);
> reds_register_channel(reds, channel);
>
> // TODO: handle seemless migration. Temp, setting migrate to
> FALSE
> @@ -1378,10 +1375,10 @@ RedWorker* red_worker_new(QXLInstance *qxl,
> reds_get_streaming
> _video(reds),
> reds_get_video_cod
> ecs(reds),
> init_info.n_surfac
> es);
> -
> channel = RED_CHANNEL(worker->display_channel);
> red_channel_set_stat_node(channel, stat_add_node(reds, worker-
> >stat, "display_channel", TRUE));
> red_channel_register_client_cbs(channel, client_display_cbs,
> dispatcher);
> + g_object_set_data(G_OBJECT(channel), "dispatcher", dispatcher);
> red_channel_set_cap(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
> red_channel_set_cap(channel,
> SPICE_DISPLAY_CAP_PREF_COMPRESSION);
> red_channel_set_cap(channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
> @@ -1398,8 +1395,8 @@ SPICE_GNUC_NORETURN static void
> *red_worker_main(void *arg)
> spice_assert(MAX_PIPE_SIZE > WIDE_CLIENT_ACK_WINDOW &&
> MAX_PIPE_SIZE > NARROW_CLIENT_ACK_WINDOW); //ensure
> wakeup by ack message
>
> - RED_CHANNEL(worker->cursor_channel)->thread_id = pthread_self();
> - RED_CHANNEL(worker->display_channel)->thread_id =
> pthread_self();
> + red_channel_reset_thread_id(RED_CHANNEL(worker-
> >cursor_channel));
> + red_channel_reset_thread_id(RED_CHANNEL(worker-
> >display_channel));
>
> GMainLoop *loop = g_main_loop_new(worker->core.main_context,
> FALSE);
> g_main_loop_run(loop);
> diff --git a/server/red-worker.h b/server/red-worker.h
> index dc2ff24..392f2c9 100644
> --- a/server/red-worker.h
> +++ b/server/red-worker.h
> @@ -30,6 +30,4 @@ RedWorker* red_worker_new(QXLInstance *qxl,
> const ClientCbs *client_display_cbs);
> bool red_worker_run(RedWorker *worker);
>
> -void red_drawable_unref(RedDrawable *red_drawable);
> -
> #endif
> diff --git a/server/reds-private.h b/server/reds-private.h
> index 36ef6c0..7fc99cc 100644
> --- a/server/reds-private.h
> +++ b/server/reds-private.h
> @@ -122,8 +122,7 @@ struct RedsState {
> between the 2 servers */
> GList *mig_target_clients;
>
> - int num_of_channels;
> - Ring channels;
> + GList *channels;
> int mouse_mode;
> int is_client_mouse_allowed;
> int dispatcher_allows_client_mouse;
> diff --git a/server/reds.c b/server/reds.c
> index fc116e0..d06e5d5 100644
> --- a/server/reds.c
> +++ b/server/reds.c
> @@ -455,15 +455,13 @@ void stat_remove_counter(RedsState *reds,
> uint64_t *counter)
> void reds_register_channel(RedsState *reds, RedChannel *channel)
> {
> spice_assert(reds);
> - ring_add(&reds->channels, &channel->link);
> - reds->num_of_channels++;
> + reds->channels = g_list_append(reds->channels, channel);
> }
>
> void reds_unregister_channel(RedsState *reds, RedChannel *channel)
> {
> - if (ring_item_is_linked(&channel->link)) {
> - ring_remove(&channel->link);
> - reds->num_of_channels--;
> + if (g_list_find(reds->channels, channel)) {
> + reds->channels = g_list_remove(reds->channels, channel);
> } else {
> spice_warning("not found");
> }
> @@ -471,11 +469,13 @@ void reds_unregister_channel(RedsState *reds,
> RedChannel *channel)
>
> static RedChannel *reds_find_channel(RedsState *reds, uint32_t type,
> uint32_t id)
> {
> - RingItem *now;
> + GList *l;
>
> - RING_FOREACH(now, &reds->channels) {
> - RedChannel *channel = SPICE_CONTAINEROF(now, RedChannel,
> link);
> - if (channel->type == type && channel->id == id) {
> + for (l = reds->channels; l != NULL; l = l->next) {
> + RedChannel *channel = l->data;
> + uint32_t this_type, this_id;
> + g_object_get(channel, "channel-type", &this_type, "id",
> &this_id, NULL);
> + if (this_type == type && this_id == id) {
> return channel;
> }
> }
> @@ -739,7 +739,7 @@ static void reds_agent_remove(RedsState *reds)
> reds->vdagent = NULL;
> reds_update_mouse_mode(reds);
> if (reds_main_channel_connected(reds) &&
> - !red_channel_is_waiting_for_migrate_data(&reds-
> >main_channel->base)) {
> + !red_channel_is_waiting_for_migrate_data(RED_CHANNEL(reds-
> >main_channel))) {
> main_channel_push_agent_disconnected(reds->main_channel);
> }
> }
> @@ -983,7 +983,9 @@ SPICE_GNUC_VISIBLE int
> spice_server_get_num_clients(SpiceServer *reds)
>
> static int channel_supports_multiple_clients(RedChannel *channel)
> {
> - switch (channel->type) {
> + uint32_t type;
> + g_object_get(channel, "channel-type", &type, NULL);
> + switch (type) {
> case SPICE_CHANNEL_MAIN:
> case SPICE_CHANNEL_DISPLAY:
> case SPICE_CHANNEL_CURSOR:
> @@ -995,23 +997,25 @@ static int
> channel_supports_multiple_clients(RedChannel *channel)
>
> static void reds_fill_channels(RedsState *reds, SpiceMsgChannels
> *channels_info)
> {
> - RingItem *now;
> + GList *l;
> int used_channels = 0;
>
> - RING_FOREACH(now, &reds->channels) {
> - RedChannel *channel = SPICE_CONTAINEROF(now, RedChannel,
> link);
> + for (l = reds->channels; l != NULL; l = l->next) {
> + uint32_t type, id;
> + RedChannel *channel = l->data;
> if (reds->num_clients > 1 &&
> !channel_supports_multiple_clients(channel)) {
> continue;
> }
> - channels_info->channels[used_channels].type = channel->type;
> - channels_info->channels[used_channels].id = channel->id;
> + g_object_get(channel, "channel-type", &type, "id", &id,
> NULL);
> + channels_info->channels[used_channels].type = type;
> + channels_info->channels[used_channels].id = id;
> used_channels++;
> }
>
> channels_info->num_of_channels = used_channels;
> - if (used_channels != reds->num_of_channels) {
> - spice_warning("sent %d out of %d", used_channels, reds-
> >num_of_channels);
> + if (used_channels != g_list_length(reds->channels)) {
> + spice_warning("sent %d out of %d", used_channels,
> g_list_length(reds->channels));
> }
> }
>
> @@ -1022,7 +1026,7 @@ SpiceMsgChannels
> *reds_msg_channels_new(RedsState *reds)
> spice_assert(reds != NULL);
>
> channels_info = (SpiceMsgChannels
> *)spice_malloc(sizeof(SpiceMsgChannels)
> - + reds->num_of_channels *
> sizeof(SpiceChannelId));
> + + g_list_length(reds->channels) *
> sizeof(SpiceChannelId));
>
> reds_fill_channels(reds, channels_info);
>
> @@ -1543,12 +1547,12 @@ static int reds_send_link_ack(RedsState
> *reds, RedLinkInfo *link)
> return FALSE;
> }
> spice_assert(reds->main_channel);
> - channel = &reds->main_channel->base;
> + channel = RED_CHANNEL(reds->main_channel);
> }
>
> reds_channel_init_auth_caps(link, channel); /* make sure common
> caps are set */
>
> - channel_caps = &channel->local_caps;
> + channel_caps = red_channel_get_local_capabilities(channel);
> ack.num_common_caps = GUINT32_TO_LE(channel_caps-
> >num_common_caps);
> ack.num_channel_caps = GUINT32_TO_LE(channel_caps->num_caps);
> hdr_size += channel_caps->num_common_caps * sizeof(uint32_t);
> @@ -1856,13 +1860,13 @@ static void reds_channel_do_link(RedChannel
> *channel, RedClient *client,
> spice_assert(stream);
>
> caps = (uint32_t *)((uint8_t *)link_msg + link_msg-
> >caps_offset);
> - channel->client_cbs.connect(channel, client, stream,
> - red_client_during_migrate_at_target(
> client),
> - link_msg->num_common_caps,
> - link_msg->num_common_caps ? caps :
> NULL,
> - link_msg->num_channel_caps,
> - link_msg->num_channel_caps ?
> - caps + link_msg->num_common_caps :
> NULL);
> + red_channel_connect(channel, client, stream,
> + red_client_during_migrate_at_target(client),
> + link_msg->num_common_caps,
> + link_msg->num_common_caps ? caps : NULL,
> + link_msg->num_channel_caps,
> + link_msg->num_channel_caps ?
> + caps + link_msg->num_common_caps : NULL);
> }
>
> /*
> @@ -3106,7 +3110,7 @@ static RedCharDevice
> *attach_to_red_agent(RedsState *reds, SpiceCharDeviceInstan
> dev->priv->plug_generation++;
>
> if (dev->priv->mig_data ||
> - red_channel_is_waiting_for_migrate_data(&reds->main_channel-
> >base)) {
> + red_channel_is_waiting_for_migrate_data(RED_CHANNEL(reds-
> >main_channel))) {
> /* Migration in progress (code is running on the destination
> host):
> * 1. Add the client to spice char device, if it was not
> already added.
> * 2.a If this (qemu-kvm state load side of migration)
> happens first
> @@ -3430,7 +3434,7 @@ static int do_spice_init(RedsState *reds,
> SpiceCoreInterface *core_interface)
> ring_init(&reds->clients);
> reds->num_clients = 0;
> reds->main_dispatcher = main_dispatcher_new(reds, reds->core);
> - ring_init(&reds->channels);
> + reds->channels = NULL;
> reds->mig_target_clients = NULL;
> reds->char_devices = NULL;
> reds->mig_wait_disconnect_clients = NULL;
> @@ -4090,7 +4094,7 @@ SPICE_GNUC_VISIBLE int
> spice_server_migrate_connect(SpiceServer *reds, const cha
> * be valid (see reds_reset_vdp for more details).
> */
> try_seamless = reds->seamless_migration_enabled &&
> - red_channel_test_remote_cap(&reds->main_channel-
> >base,
> + red_channel_test_remote_cap(RED_CHANNEL(reds-
> >main_channel),
> SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS);
> /* main channel will take care of clients that are still during
> migration (at target)*/
> if (main_channel_migrate_connect(reds->main_channel, reds-
> >config->mig_spice,
> diff --git a/server/smartcard.c b/server/smartcard.c
> index 13eed80..6974cb1 100644
> --- a/server/smartcard.c
> +++ b/server/smartcard.c
> @@ -49,9 +49,73 @@
> // Maximal length of APDU
> #define APDUBufSize 270
>
> +#define RED_TYPE_SMARTCARD_CHANNEL red_smartcard_channel_get_type()
> +
> +#define RED_SMARTCARD_CHANNEL(obj) \
> + (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_SMARTCARD_CHANNEL,
> RedSmartcardChannel))
> +#define RED_SMARTCARD_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_SMARTCARD_CHANNEL,
> RedSmartcardChannelClass))
> +#define RED_IS_SMARTCARD_CHANNEL(obj) \
> + (G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_SMARTCARD_CHANNEL))
> +#define RED_IS_SMARTCARD_CHANNEL_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_SMARTCARD_CHANNEL))
> +#define RED_SMARTCARD_CHANNEL_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_SMARTCARD_CHANNEL,
> RedSmartcardChannelClass))
> +
> +typedef struct RedSmartcardChannel RedSmartcardChannel;
> +typedef struct RedSmartcardChannelClass RedSmartcardChannelClass;
> +typedef struct RedSmartcardChannelPrivate
> RedSmartcardChannelPrivate;
> +
> +struct RedSmartcardChannel
> +{
> + RedChannel parent;
> +
> + RedSmartcardChannelPrivate *priv;
> +};
> +
> +struct RedSmartcardChannelClass
> +{
> + RedChannelClass parent_class;
> +};
> +
> +GType red_smartcard_channel_get_type(void) G_GNUC_CONST;
> +
> +G_DEFINE_TYPE(RedSmartcardChannel, red_smartcard_channel,
> RED_TYPE_CHANNEL)
> +
> +#define SMARTCARD_CHANNEL_PRIVATE(o) \
> + (G_TYPE_INSTANCE_GET_PRIVATE((o), RED_TYPE_SMARTCARD_CHANNEL,
> RedSmartcardChannelPrivate))
> +
> +struct RedSmartcardChannelPrivate
> +{
> + gpointer padding;
> +};
> +
> +static void
> +red_smartcard_channel_init(RedSmartcardChannel *self)
> +{
> + self->priv = SMARTCARD_CHANNEL_PRIVATE(self);
> +}
> +
> +static RedSmartcardChannel *
> +red_smartcard_channel_new(RedsState *reds)
> +{
> + return g_object_new(RED_TYPE_SMARTCARD_CHANNEL,
> + "spice-server", reds,
> + "core-interface",
> reds_get_core_interface(reds),
> + "channel-type", SPICE_CHANNEL_SMARTCARD,
> + "id", 0,
> + "handle-acks", FALSE /* handle_acks */,
> + "migration-flags",
> + (SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER),
> + NULL);
> +}
> +
> +
> G_DEFINE_TYPE(RedCharDeviceSmartcard, red_char_device_smartcard,
> RED_TYPE_CHAR_DEVICE)
>
> -#define RED_CHAR_DEVICE_SMARTCARD_PRIVATE(o)
> (G_TYPE_INSTANCE_GET_PRIVATE ((o), RED_TYPE_CHAR_DEVICE_SMARTCARD,
> RedCharDeviceSmartcardPrivate))
> +#define RED_CHAR_DEVICE_SMARTCARD_PRIVATE(o) \
> + (G_TYPE_INSTANCE_GET_PRIVATE ((o),
> RED_TYPE_CHAR_DEVICE_SMARTCARD, \
> + RedCharDeviceSmartcardPrivate))
>
> struct RedCharDeviceSmartcardPrivate {
> uint32_t reader_id;
> @@ -74,10 +138,6 @@ typedef struct RedMsgItem {
> static RedMsgItem *smartcard_get_vsc_msg_item(RedChannelClient *rcc,
> VSCMsgHeader *vheader);
> static void smartcard_channel_client_pipe_add_push(RedChannelClient
> *rcc, RedPipeItem *item);
>
> -typedef struct SmartCardChannel {
> - RedChannel base;
> -} SmartCardChannel;
> -
> static struct Readers {
> uint32_t num;
> SpiceCharDeviceInstance* sin[SMARTCARD_MAX_READERS];
> @@ -519,41 +579,51 @@ static void smartcard_connect_client(RedChannel
> *channel, RedClient *client,
> }
> }
>
> -SmartCardChannel *g_smartcard_channel;
> -
> -static void smartcard_init(RedsState *reds)
> +static void
> +red_smartcard_channel_constructed(GObject *object)
> {
> - ChannelCbs channel_cbs = { NULL, };
> + RedSmartcardChannel *self = RED_SMARTCARD_CHANNEL(object);
> + RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
> ClientCbs client_cbs = { NULL, };
> - uint32_t migration_flags = SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER;
> -
> - spice_assert(!g_smartcard_channel);
>
> - channel_cbs.config_socket =
> smartcard_channel_client_config_socket;
> - channel_cbs.on_disconnect =
> smartcard_channel_client_on_disconnect;
> - channel_cbs.send_item = smartcard_channel_send_item;
> - channel_cbs.alloc_recv_buf =
> smartcard_channel_client_alloc_msg_rcv_buf;
> - channel_cbs.release_recv_buf =
> smartcard_channel_client_release_msg_rcv_buf;
> - channel_cbs.handle_migrate_flush_mark =
> smartcard_channel_client_handle_migrate_flush_mark;
> - channel_cbs.handle_migrate_data =
> smartcard_channel_client_handle_migrate_data;
> -
> - g_smartcard_channel =
> (SmartCardChannel*)red_channel_create(sizeof(SmartCardChannel),
> - reds,
> - reds_get_core_interface
> (reds),
> - SPICE_CHANNEL_SMARTCARD
> , 0,
> - FALSE /* handle_acks
> */,
> - smartcard_channel_clien
> t_handle_message,
> - &channel_cbs,
> - migration_flags);
> -
> - if (!g_smartcard_channel) {
> - spice_error("failed to allocate Smartcard Channel");
> - }
> + G_OBJECT_CLASS(red_smartcard_channel_parent_class)-
> >constructed(object);
>
> client_cbs.connect = smartcard_connect_client;
> - red_channel_register_client_cbs(&g_smartcard_channel->base,
> &client_cbs, NULL);
> + red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs,
> NULL);
> +
> + reds_register_channel(reds, RED_CHANNEL(self));
> +}
> +
> +static void
> +red_smartcard_channel_class_init(RedSmartcardChannelClass *klass)
> +{
> + GObjectClass *object_class = G_OBJECT_CLASS(klass);
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + g_type_class_add_private(klass,
> sizeof(RedSmartcardChannelPrivate));
> +
> + object_class->constructed = red_smartcard_channel_constructed;
> +
> + channel_class->handle_message =
> smartcard_channel_client_handle_message,
> +
> + channel_class->config_socket =
> smartcard_channel_client_config_socket;
> + channel_class->on_disconnect =
> smartcard_channel_client_on_disconnect;
> + channel_class->send_item = smartcard_channel_send_item;
> + channel_class->alloc_recv_buf =
> smartcard_channel_client_alloc_msg_rcv_buf;
> + channel_class->release_recv_buf =
> smartcard_channel_client_release_msg_rcv_buf;
> + channel_class->handle_migrate_flush_mark =
> smartcard_channel_client_handle_migrate_flush_mark;
> + channel_class->handle_migrate_data =
> smartcard_channel_client_handle_migrate_data;
> +
> +}
> +
> +/* FIXME: remove global */
> +RedSmartcardChannel *g_smartcard_channel;
> +
> +static void smartcard_init(RedsState *reds)
> +{
> + spice_assert(!g_smartcard_channel);
>
> - reds_register_channel(reds, &g_smartcard_channel->base);
> + g_smartcard_channel = red_smartcard_channel_new(reds);
> }
>
>
> diff --git a/server/sound.c b/server/sound.c
> index db23e95..9edfa8a 100644
> --- a/server/sound.c
> +++ b/server/sound.c
> @@ -31,6 +31,7 @@
>
> #include "spice.h"
> #include "red-common.h"
> +#include "dummy-channel.h"
> #include "dummy-channel-client.h"
> #include "main-channel.h"
> #include "reds.h"
> @@ -218,6 +219,7 @@ static void snd_disconnect_channel(SndChannel
> *channel)
> SndWorker *worker;
> RedsState *reds;
> RedChannel *red_channel;
> + uint32_t type;
>
> if (!channel || !channel->stream) {
> spice_debug("not connected");
> @@ -225,8 +227,9 @@ static void snd_disconnect_channel(SndChannel
> *channel)
> }
> red_channel = red_channel_client_get_channel(channel-
> >channel_client);
> reds = snd_channel_get_server(channel);
> + g_object_get(red_channel, "channel-type", &type, NULL);
> spice_debug("SndChannel=%p rcc=%p type=%d",
> - channel, channel->channel_client, red_channel-
> >type);
> + channel, channel->channel_client, type);
> worker = channel->worker;
> channel->cleanup(channel);
> red_channel_client_disconnect(worker->connection-
> >channel_client);
> @@ -998,12 +1001,14 @@ static void
> snd_disconnect_channel_client(RedChannelClient *rcc)
> {
> SndWorker *worker;
> RedChannel *channel = red_channel_client_get_channel(rcc);
> + uint32_t type;
>
> spice_assert(channel);
> - spice_assert(channel->data);
> - worker = (SndWorker *)channel->data;
> + worker = (SndWorker *)g_object_get_data(G_OBJECT(channel),
> "sound-worker");
> + spice_assert(worker);
> + g_object_get(channel, "channel-type", &type, NULL);
>
> - spice_debug("channel-type=%d", channel->type);
> + spice_debug("channel-type=%d", type);
> if (worker->connection) {
> spice_assert(worker->connection->channel_client == rcc);
> snd_disconnect_channel(worker->connection);
> @@ -1058,6 +1063,7 @@ SPICE_GNUC_VISIBLE void
> spice_server_playback_start(SpicePlaybackInstance *sin)
> sin->st->worker.active = 1;
> if (!channel)
> return;
> +
> spice_assert(!playback_channel->base.active);
> reds_disable_mm_time(snd_channel_get_server(channel));
> playback_channel->base.active = TRUE;
> @@ -1077,6 +1083,7 @@ SPICE_GNUC_VISIBLE void
> spice_server_playback_stop(SpicePlaybackInstance *sin)
> sin->st->worker.active = 0;
> if (!channel)
> return;
> +
> spice_assert(playback_channel->base.active);
> reds_enable_mm_time(snd_channel_get_server(channel));
> playback_channel->base.active = FALSE;
> @@ -1145,7 +1152,9 @@ void snd_set_playback_latency(RedClient
> *client, uint32_t latency)
> SndWorker *now = workers;
>
> for (; now; now = now->next) {
> - if (now->base_channel->type == SPICE_CHANNEL_PLAYBACK &&
> now->connection &&
> + uint32_t type;
> + g_object_get(now->base_channel, "channel-type", &type,
> NULL);
> + if (type == SPICE_CHANNEL_PLAYBACK && now->connection &&
> red_channel_client_get_client(now->connection-
> >channel_client) == client) {
>
> if (red_channel_client_test_remote_cap(now->connection-
> >channel_client,
> @@ -1213,7 +1222,7 @@ static void snd_set_playback_peer(RedChannel
> *channel, RedClient *client, RedsSt
> int migration, int
> num_common_caps, uint32_t *common_caps,
> int num_caps, uint32_t *caps)
> {
> - SndWorker *worker = channel->data;
> + SndWorker *worker = g_object_get_data(G_OBJECT(channel), "sound-
> worker");
> PlaybackChannel *playback_channel;
> SpicePlaybackState *st = SPICE_CONTAINEROF(worker,
> SpicePlaybackState, worker);
>
> @@ -1242,7 +1251,8 @@ static void snd_set_playback_peer(RedChannel
> *channel, RedClient *client, RedsSt
> SPICE_PLAYBACK_CAP_CELT_0_
> 5_1);
> int client_can_opus =
> red_channel_client_test_remote_cap(playback_channel-
> >base.channel_client,
> SPICE_PLAYBACK_CAP_OPUS);
> - int playback_compression =
> reds_config_get_playback_compression(channel->reds);
> + int playback_compression =
> + reds_config_get_playback_compression(red_channel_get_server(
> channel));
> int desired_mode = snd_desired_audio_mode(playback_compression,
> st->frequency,
> client_can_celt,
> client_can_opus);
> playback_channel->mode = SPICE_AUDIO_DATA_MODE_RAW;
> @@ -1271,8 +1281,8 @@ static void
> snd_record_migrate_channel_client(RedChannelClient *rcc)
>
> spice_debug(NULL);
> spice_assert(channel);
> - spice_assert(channel->data);
> - worker = (SndWorker *)channel->data;
> + worker = (SndWorker *)g_object_get_data(G_OBJECT(channel),
> "sound-worker");
> + spice_assert(worker);
>
> if (worker->connection) {
> spice_assert(worker->connection->channel_client == rcc);
> @@ -1462,7 +1472,7 @@ static void snd_set_record_peer(RedChannel
> *channel, RedClient *client, RedsStre
> int migration, int num_common_caps,
> uint32_t *common_caps,
> int num_caps, uint32_t *caps)
> {
> - SndWorker *worker = channel->data;
> + SndWorker *worker = g_object_get_data(G_OBJECT(channel), "sound-
> worker");
> RecordChannel *record_channel;
> SpiceRecordState *st = SPICE_CONTAINEROF(worker,
> SpiceRecordState, worker);
>
> @@ -1500,8 +1510,8 @@ static void
> snd_playback_migrate_channel_client(RedChannelClient *rcc)
> RedChannel *channel = red_channel_client_get_channel(rcc);
>
> spice_assert(channel);
> - spice_assert(channel->data);
> - worker = (SndWorker *)channel->data;
> + worker = (SndWorker *)g_object_get_data(G_OBJECT(channel),
> "sound-worker");
> + spice_assert(worker);
> spice_debug(NULL);
>
> if (worker->connection) {
> @@ -1542,8 +1552,9 @@ void snd_attach_playback(RedsState *reds,
> SpicePlaybackInstance *sin)
> sin->st->frequency = SND_CODEC_CELT_PLAYBACK_FREQ; /* Default to
> the legacy rate */
>
> // TODO: Make RedChannel base of worker? instead of assigning it
> to channel->data
> - channel = red_channel_create_dummy(sizeof(RedChannel), reds,
> SPICE_CHANNEL_PLAYBACK, 0);
> + channel = dummy_channel_new(reds, SPICE_CHANNEL_PLAYBACK, 0);
>
> + g_object_set_data(G_OBJECT(channel), "sound-worker",
> playback_worker);
> client_cbs.connect = snd_set_playback_peer;
> client_cbs.disconnect = snd_disconnect_channel_client;
> client_cbs.migrate = snd_playback_migrate_channel_client;
> @@ -1571,8 +1582,9 @@ void snd_attach_record(RedsState *reds,
> SpiceRecordInstance *sin)
> sin->st->frequency = SND_CODEC_CELT_PLAYBACK_FREQ; /* Default to
> the legacy rate */
>
> // TODO: Make RedChannel base of worker? instead of assigning it
> to channel->data
> - channel = red_channel_create_dummy(sizeof(RedChannel), reds,
> SPICE_CHANNEL_RECORD, 0);
> + channel = dummy_channel_new(reds, SPICE_CHANNEL_RECORD, 0);
>
> + g_object_set_data(G_OBJECT(channel), "sound-worker",
> record_worker);
> client_cbs.connect = snd_set_record_peer;
> client_cbs.disconnect = snd_disconnect_channel_client;
> client_cbs.migrate = snd_record_migrate_channel_client;
> @@ -1628,7 +1640,9 @@ void snd_set_playback_compression(int on)
> SndWorker *now = workers;
>
> for (; now; now = now->next) {
> - if (now->base_channel->type == SPICE_CHANNEL_PLAYBACK &&
> now->connection) {
> + uint32_t type;
> + g_object_get(now->base_channel, "channel-type", &type,
> NULL);
> + if (type == SPICE_CHANNEL_PLAYBACK && now->connection) {
> PlaybackChannel* playback = (PlaybackChannel*)now-
> >connection;
> SpicePlaybackState *st = SPICE_CONTAINEROF(now,
> SpicePlaybackState, worker);
> int client_can_celt =
> red_channel_client_test_remote_cap(playback->base.channel_client,
> diff --git a/server/spicevmc.c b/server/spicevmc.c
> index e710111..d92a0fe 100644
> --- a/server/spicevmc.c
> +++ b/server/spicevmc.c
> @@ -57,23 +57,18 @@ typedef struct RedVmcPipeItem {
> uint32_t buf_used;
> } RedVmcPipeItem;
>
> -typedef struct SpiceVmcState {
> - RedChannel channel; /* Must be the first item */
> - RedChannelClient *rcc;
> - RedCharDevice *chardev;
> - SpiceCharDeviceInstance *chardev_sin;
> - RedVmcPipeItem *pipe_item;
> - RedCharDeviceWriteBuffer *recv_from_client_buf;
> - uint8_t port_opened;
> -} SpiceVmcState;
> -
> #define RED_TYPE_CHAR_DEVICE_SPICEVMC
> red_char_device_spicevmc_get_type()
>
> -#define RED_CHAR_DEVICE_SPICEVMC(obj)
> (G_TYPE_CHECK_INSTANCE_CAST((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC,
> RedCharDeviceSpiceVmc))
> -#define RED_CHAR_DEVICE_SPICEVMC_CLASS(klass)
> (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHAR_DEVICE_SPICEVMC,
> RedCharDeviceSpiceVmcClass))
> -#define RED_IS_CHAR_DEVICE_SPICEVMC(obj)
> (G_TYPE_CHECK_INSTANCE_TYPE((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC))
> -#define RED_IS_CHAR_DEVICE_SPICEVMC_CLASS(klass)
> (G_TYPE_CHECK_CLASS_TYPE((klass), RED_TYPE_CHAR_DEVICE_SPICEVMC))
> -#define RED_CHAR_DEVICE_SPICEVMC_GET_CLASS(obj)
> (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC,
> RedCharDeviceSpiceVmcClass))
> +#define RED_CHAR_DEVICE_SPICEVMC(obj) \
> + (G_TYPE_CHECK_INSTANCE_CAST((obj),
> RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmc))
> +#define RED_CHAR_DEVICE_SPICEVMC_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), RED_TYPE_CHAR_DEVICE_SPICEVMC,
> RedCharDeviceSpiceVmcClass))
> +#define RED_IS_CHAR_DEVICE_SPICEVMC(obj) \
> + (G_TYPE_CHECK_INSTANCE_TYPE((obj),
> RED_TYPE_CHAR_DEVICE_SPICEVMC))
> +#define RED_IS_CHAR_DEVICE_SPICEVMC_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_TYPE((klass),
> RED_TYPE_CHAR_DEVICE_SPICEVMC))
> +#define RED_CHAR_DEVICE_SPICEVMC_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), RED_TYPE_CHAR_DEVICE_SPICEVMC,
> RedCharDeviceSpiceVmcClass))
>
> typedef struct RedCharDeviceSpiceVmc RedCharDeviceSpiceVmc;
> typedef struct RedCharDeviceSpiceVmcClass
> RedCharDeviceSpiceVmcClass;
> @@ -94,6 +89,213 @@ static RedCharDevice
> *red_char_device_spicevmc_new(SpiceCharDeviceInstance *sin,
>
> G_DEFINE_TYPE(RedCharDeviceSpiceVmc, red_char_device_spicevmc,
> RED_TYPE_CHAR_DEVICE)
>
> +#define RED_CHAR_DEVICE_SPICEVMC_PRIVATE(o) \
> + (G_TYPE_INSTANCE_GET_PRIVATE ((o),
> RED_TYPE_CHAR_DEVICE_SPICEVMC, RedCharDeviceSpiceVmcPrivate))
> +
> +#define SPICE_TYPE_VMC_STATE spice_vmc_state_get_type()
> +
> +#define SPICE_VMC_STATE(obj) \
> + (G_TYPE_CHECK_INSTANCE_CAST((obj), SPICE_TYPE_VMC_STATE,
> SpiceVmcState))
> +#define SPICE_VMC_STATE_CLASS(klass) \
> + (G_TYPE_CHECK_CLASS_CAST((klass), SPICE_TYPE_VMC_STATE,
> SpiceVmcStateClass))
> +#define SPICE_IS_VMC_STATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),
> SPICE_TYPE_VMC_STATE))
> +#define SPICE_IS_VMC_STATE_CLASS(klass)
> (G_TYPE_CHECK_CLASS_TYPE((klass), SPICE_TYPE_VMC_STATE))
> +#define SPICE_VMC_STATE_GET_CLASS(obj) \
> + (G_TYPE_INSTANCE_GET_CLASS((obj), SPICE_TYPE_VMC_STATE,
> SpiceVmcStateClass))
> +
> +typedef struct SpiceVmcState SpiceVmcState;
> +typedef struct SpiceVmcStateClass SpiceVmcStateClass;
> +typedef struct SpiceVmcStatePrivate SpiceVmcStatePrivate;
> +
> +struct SpiceVmcState
> +{
> + RedChannel parent;
> +
> + SpiceVmcStatePrivate *priv;
> +};
> +
> +struct SpiceVmcStateClass
> +{
> + RedChannelClass parent_class;
> +};
> +
> +GType spice_vmc_state_get_type(void) G_GNUC_CONST;
> +
> +G_DEFINE_TYPE(SpiceVmcState, spice_vmc_state, RED_TYPE_CHANNEL)
> +
> +
> +#define SPICE_TYPE_VMC_STATE_USBREDIR
> spice_vmc_state_usbredir_get_type()
> +typedef struct
> +{
> + SpiceVmcState parent;
> +} SpiceVmcStateUsbredir;
> +
> +typedef struct
> +{
> + SpiceVmcStateClass parent_class;
> +} SpiceVmcStateUsbredirClass;
> +
> +GType spice_vmc_state_usbredir_get_type(void) G_GNUC_CONST;
> +static void spice_vmc_state_usbredir_init(SpiceVmcStateUsbredir
> *self)
> +{
> +}
> +G_DEFINE_TYPE(SpiceVmcStateUsbredir, spice_vmc_state_usbredir,
> SPICE_TYPE_VMC_STATE)
> +
> +
> +#define SPICE_TYPE_VMC_STATE_WEBDAV
> spice_vmc_state_webdav_get_type()
> +typedef struct
> +{
> + SpiceVmcState parent;
> +} SpiceVmcStateWebdav;
> +
> +typedef struct
> +{
> + SpiceVmcStateClass parent_class;
> +} SpiceVmcStateWebdavClass;
> +
> +GType spice_vmc_state_webdav_get_type(void) G_GNUC_CONST;
> +static void spice_vmc_state_webdav_init(SpiceVmcStateWebdav *self)
> +{
> +}
> +G_DEFINE_TYPE(SpiceVmcStateWebdav, spice_vmc_state_webdav,
> SPICE_TYPE_VMC_STATE)
> +
> +
> +#define SPICE_TYPE_VMC_STATE_PORT spice_vmc_state_port_get_type()
> +typedef struct
> +{
> + SpiceVmcState parent;
> +} SpiceVmcStatePort;
> +
> +typedef struct
> +{
> + SpiceVmcStateClass parent_class;
> +} SpiceVmcStatePortClass;
> +
> +GType spice_vmc_state_port_get_type(void) G_GNUC_CONST;
> +static void spice_vmc_state_port_init(SpiceVmcStatePort *self)
> +{
> +}
> +G_DEFINE_TYPE(SpiceVmcStatePort, spice_vmc_state_port,
> SPICE_TYPE_VMC_STATE)
> +
> +#define VMC_STATE_PRIVATE(o) \
> + (G_TYPE_INSTANCE_GET_PRIVATE((o), SPICE_TYPE_VMC_STATE,
> SpiceVmcStatePrivate))
> +
> +struct SpiceVmcStatePrivate
> +{
> + RedChannelClient *rcc;
> + RedCharDevice *chardev;
> + SpiceCharDeviceInstance *chardev_sin;
> + RedVmcPipeItem *pipe_item;
> + RedCharDeviceWriteBuffer *recv_from_client_buf;
> + uint8_t port_opened;
> +};
> +
> +enum {
> + PROP0,
> + PROP_DEVICE_INSTANCE
> +};
> +
> +static void
> +spice_vmc_state_get_property(GObject *object,
> + guint property_id,
> + GValue *value,
> + GParamSpec *pspec)
> +{
> + SpiceVmcState *self = SPICE_VMC_STATE(object);
> +
> + switch (property_id)
> + {
> + case PROP_DEVICE_INSTANCE:
> + g_value_set_pointer(value, self->priv->chardev_sin);
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id,
> pspec);
> + }
> +}
> +
> +static void
> +spice_vmc_state_set_property(GObject *object,
> + guint property_id,
> + const GValue *value,
> + GParamSpec *pspec)
> +{
> + SpiceVmcState *self = SPICE_VMC_STATE(object);
> +
> + switch (property_id)
> + {
> + case PROP_DEVICE_INSTANCE:
> + self->priv->chardev_sin = g_value_get_pointer(value);
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id,
> pspec);
> + }
> +}
> +
> +static void spicevmc_connect(RedChannel *channel, RedClient *client,
> + RedsStream *stream, int migration, int
> num_common_caps,
> + uint32_t *common_caps, int num_caps,
> uint32_t *caps);
> +
> +static void
> +spice_vmc_state_constructed(GObject *object)
> +{
> + SpiceVmcState *self = SPICE_VMC_STATE(object);
> + ClientCbs client_cbs = { NULL, };
> + RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
> +
> + G_OBJECT_CLASS(spice_vmc_state_parent_class)-
> >constructed(object);
> +
> + client_cbs.connect = spicevmc_connect;
> + red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs,
> NULL);
> +
> +#ifdef USE_LZ4
> + red_channel_set_cap(RED_CHANNEL(self),
> SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4);
> +#endif
> +
> + red_channel_init_outgoing_messages_window(RED_CHANNEL(self));
> +
> + self->priv->chardev = red_char_device_spicevmc_new(self->priv-
> >chardev_sin,
> + reds,
> self);
> +
> + reds_register_channel(reds, RED_CHANNEL(self));
> +}
> +
> +static void
> +spice_vmc_state_init(SpiceVmcState *self)
> +{
> + self->priv = VMC_STATE_PRIVATE(self);
> +}
> +
> +static SpiceVmcState *spice_vmc_state_new(RedsState *reds, uint8_t
> channel_type,
> + SpiceCharDeviceInstance
> *sin)
> +{
> + GType gtype = G_TYPE_NONE;
> + static uint8_t id[256] = { 0, };
> +
> + switch (channel_type) {
> + case SPICE_CHANNEL_USBREDIR:
> + gtype = SPICE_TYPE_VMC_STATE_USBREDIR;
> + break;
> + case SPICE_CHANNEL_WEBDAV:
> + gtype = SPICE_TYPE_VMC_STATE_WEBDAV;
> + break;
> + case SPICE_CHANNEL_PORT:
> + gtype = SPICE_TYPE_VMC_STATE_PORT;
> + break;
> + default:
> + g_error("Unsupported channel_type for
> spice_vmc_state_new(): %u", channel_type);
> + }
> + return g_object_new(gtype,
> + "spice-server", reds,
> + "core-interface",
> reds_get_core_interface(reds),
> + "channel-type", channel_type,
> + "id", id[channel_type]++,
> + "handle-acks", FALSE,
> + "migration-flags",
> + (SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER),
> + "device-instance", sin,
> + NULL);
> +}
> +
> typedef struct RedPortInitPipeItem {
> RedPipeItem base;
> char* name;
> @@ -128,7 +330,7 @@ static RedVmcPipeItem*
> try_compress_lz4(SpiceVmcState *state, int n, RedVmcPipeI
> RedVmcPipeItem *msg_item_compressed;
> int compressed_data_count;
>
> - if (reds_stream_get_family(red_channel_client_get_stream(state-
> >rcc)) == AF_UNIX) {
> + if (reds_stream_get_family(red_channel_client_get_stream(state-
> >priv->rcc)) == AF_UNIX) {
> /* AF_LOCAL - data will not be compressed */
> return NULL;
> }
> @@ -136,7 +338,7 @@ static RedVmcPipeItem*
> try_compress_lz4(SpiceVmcState *state, int n, RedVmcPipeI
> /* n <= threshold - data will not be compressed */
> return NULL;
> }
> - if (!red_channel_test_remote_cap(&state->channel,
> SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4)) {
> + if (!red_channel_test_remote_cap(RED_CHANNEL(state),
> SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4)) {
> /* Client doesn't have compression cap - data will not be
> compressed */
> return NULL;
> }
> @@ -171,18 +373,18 @@ static RedPipeItem
> *spicevmc_chardev_read_msg_from_dev(SpiceCharDeviceInstance *
>
> sif = spice_char_device_get_interface(sin);
>
> - if (!state->rcc) {
> + if (!state->priv->rcc) {
> return NULL;
> }
>
> - if (!state->pipe_item) {
> + if (!state->priv->pipe_item) {
> msg_item = spice_new0(RedVmcPipeItem, 1);
> msg_item->type = SPICE_DATA_COMPRESSION_TYPE_NONE;
> red_pipe_item_init(&msg_item->base,
> RED_PIPE_ITEM_TYPE_SPICEVMC_DATA);
> } else {
> - spice_assert(state->pipe_item->buf_used == 0);
> - msg_item = state->pipe_item;
> - state->pipe_item = NULL;
> + spice_assert(state->priv->pipe_item->buf_used == 0);
> + msg_item = state->priv->pipe_item;
> + state->priv->pipe_item = NULL;
> }
>
> n = sif->read(sin, msg_item->buf,
> @@ -201,7 +403,7 @@ static RedPipeItem
> *spicevmc_chardev_read_msg_from_dev(SpiceCharDeviceInstance *
> msg_item->buf_used = n;
> return &msg_item->base;
> } else {
> - state->pipe_item = msg_item;
> + state->priv->pipe_item = msg_item;
> return NULL;
> }
> }
> @@ -212,26 +414,26 @@ static void
> spicevmc_chardev_send_msg_to_client(RedPipeItem *msg,
> {
> SpiceVmcState *state = opaque;
>
> - spice_assert(red_channel_client_get_client(state->rcc) ==
> client);
> + spice_assert(red_channel_client_get_client(state->priv->rcc) ==
> client);
> red_pipe_item_ref(msg);
> - red_channel_client_pipe_add_push(state->rcc, msg);
> + red_channel_client_pipe_add_push(state->priv->rcc, msg);
> }
>
> static SpiceVmcState
> *spicevmc_red_channel_client_get_state(RedChannelClient *rcc)
> {
> RedChannel *channel = red_channel_client_get_channel(rcc);
> - return SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
> + return SPICE_VMC_STATE(channel);
> }
>
> static void spicevmc_port_send_init(RedChannelClient *rcc)
> {
> SpiceVmcState *state =
> spicevmc_red_channel_client_get_state(rcc);
> - SpiceCharDeviceInstance *sin = state->chardev_sin;
> + SpiceCharDeviceInstance *sin = state->priv->chardev_sin;
> RedPortInitPipeItem *item =
> spice_malloc(sizeof(RedPortInitPipeItem));
>
> red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_PORT_INIT);
> item->name = strdup(sin->portname);
> - item->opened = state->port_opened;
> + item->opened = state->priv->port_opened;
> red_channel_client_pipe_add_push(rcc, &item->base);
> }
>
> @@ -256,10 +458,10 @@ static void
> spicevmc_char_dev_remove_client(RedClient *client, void *opaque)
> SpiceVmcState *state = opaque;
>
> spice_printerr("vmc state %p, client %p", state, client);
> - spice_assert(state->rcc &&
> - red_channel_client_get_client(state->rcc) ==
> client);
> + spice_assert(state->priv->rcc &&
> + red_channel_client_get_client(state->priv->rcc) ==
> client);
>
> - red_channel_client_shutdown(state->rcc);
> + red_channel_client_shutdown(state->priv->rcc);
> }
>
> static int
> spicevmc_red_channel_client_config_socket(RedChannelClient *rcc)
> @@ -267,8 +469,10 @@ static int
> spicevmc_red_channel_client_config_socket(RedChannelClient *rcc)
> int delay_val = 1;
> RedsStream *stream = red_channel_client_get_stream(rcc);
> RedChannel *channel = red_channel_client_get_channel(rcc);
> + uint32_t type;
>
> - if (channel->type == SPICE_CHANNEL_USBREDIR) {
> + g_object_get(channel, "channel-type", &type, NULL);
> + if (type == SPICE_CHANNEL_USBREDIR) {
> if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY,
> &delay_val, sizeof(delay_val)) != 0) {
> if (errno != ENOTSUP && errno != ENOPROTOOPT) {
> @@ -294,14 +498,14 @@ static void
> spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc)
> state = spicevmc_red_channel_client_get_state(rcc);
>
> /* partial message which wasn't pushed to device */
> - red_char_device_write_buffer_release(state->chardev, &state-
> >recv_from_client_buf);
> + red_char_device_write_buffer_release(state->priv->chardev,
> &state->priv->recv_from_client_buf);
>
> - if (state->chardev) {
> - if (red_char_device_client_exists(state->chardev, client)) {
> - red_char_device_client_remove(state->chardev, client);
> + if (state->priv->chardev) {
> + if (red_char_device_client_exists(state->priv->chardev,
> client)) {
> + red_char_device_client_remove(state->priv->chardev,
> client);
> } else {
> spice_printerr("client %p have already been removed from
> char dev %p",
> - client, state->chardev);
> + client, state->priv->chardev);
> }
> }
>
> @@ -310,10 +514,10 @@ static void
> spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc)
> if (!red_channel_client_is_destroying(rcc))
> red_channel_client_destroy(rcc);
>
> - state->rcc = NULL;
> - sif = spice_char_device_get_interface(state->chardev_sin);
> + state->priv->rcc = NULL;
> + sif = spice_char_device_get_interface(state->priv->chardev_sin);
> if (sif->state) {
> - sif->state(state->chardev_sin, 0);
> + sif->state(state->priv->chardev_sin, 0);
> }
> }
>
> @@ -342,7 +546,7 @@ static int
> spicevmc_channel_client_handle_migrate_data(RedChannelClient *rcc,
> spice_error("bad header");
> return FALSE;
> }
> - return red_char_device_restore(state->chardev, &mig_data->base);
> + return red_char_device_restore(state->priv->chardev, &mig_data-
> >base);
> }
>
> static int handle_compressed_msg(SpiceVmcState *state,
> RedChannelClient *rcc,
> @@ -352,7 +556,7 @@ static int handle_compressed_msg(SpiceVmcState
> *state, RedChannelClient *rcc,
> int decompressed_size;
> RedCharDeviceWriteBuffer *write_buf;
>
> - write_buf = red_char_device_write_buffer_get(state->chardev,
> + write_buf = red_char_device_write_buffer_get(state->priv-
> >chardev,
> red_channel_client_
> get_client(rcc),
> compressed_data_msg
> ->uncompressed_size);
> if (!write_buf) {
> @@ -372,16 +576,16 @@ static int handle_compressed_msg(SpiceVmcState
> *state, RedChannelClient *rcc,
> #endif
> default:
> spice_warning("Invalid Compression Type");
> - red_char_device_write_buffer_release(state->chardev,
> &write_buf);
> + red_char_device_write_buffer_release(state->priv->chardev,
> &write_buf);
> return FALSE;
> }
> if (decompressed_size != compressed_data_msg->uncompressed_size)
> {
> spice_warning("Decompression Error");
> - red_char_device_write_buffer_release(state->chardev,
> &write_buf);
> + red_char_device_write_buffer_release(state->priv->chardev,
> &write_buf);
> return FALSE;
> }
> write_buf->buf_used = decompressed_size;
> - red_char_device_write_buffer_add(state->chardev, write_buf);
> + red_char_device_write_buffer_add(state->priv->chardev,
> write_buf);
> return TRUE;
> }
>
> @@ -396,14 +600,14 @@ static int
> spicevmc_red_channel_client_handle_message_parsed(RedChannelClient *r
> SpiceCharDeviceInterface *sif;
>
> state = spicevmc_red_channel_client_get_state(rcc);
> - sif = spice_char_device_get_interface(state->chardev_sin);
> + sif = spice_char_device_get_interface(state->priv->chardev_sin);
>
> switch (type) {
> case SPICE_MSGC_SPICEVMC_DATA:
> - spice_assert(state->recv_from_client_buf->buf == msg);
> - state->recv_from_client_buf->buf_used = size;
> - red_char_device_write_buffer_add(state->chardev, state-
> >recv_from_client_buf);
> - state->recv_from_client_buf = NULL;
> + spice_assert(state->priv->recv_from_client_buf->buf == msg);
> + state->priv->recv_from_client_buf->buf_used = size;
> + red_char_device_write_buffer_add(state->priv->chardev,
> state->priv->recv_from_client_buf);
> + state->priv->recv_from_client_buf = NULL;
> break;
> case SPICE_MSGC_SPICEVMC_COMPRESSED_DATA:
> return handle_compressed_msg(state, rcc,
> (SpiceMsgCompressedData*)msg);
> @@ -414,7 +618,7 @@ static int
> spicevmc_red_channel_client_handle_message_parsed(RedChannelClient *r
> return FALSE;
> }
> if (sif->base.minor_version >= 2 && sif->event != NULL)
> - sif->event(state->chardev_sin, *(uint8_t*)msg);
> + sif->event(state->priv->chardev_sin, *(uint8_t*)msg);
> break;
> default:
> return red_channel_client_handle_message(rcc, size, type,
> (uint8_t*)msg);
> @@ -434,16 +638,16 @@ static uint8_t
> *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
>
> switch (type) {
> case SPICE_MSGC_SPICEVMC_DATA:
> - assert(!state->recv_from_client_buf);
> + assert(!state->priv->recv_from_client_buf);
>
> - state->recv_from_client_buf =
> red_char_device_write_buffer_get(state->chardev,
> -
> client,
> -
> size);
> - if (!state->recv_from_client_buf) {
> + state->priv->recv_from_client_buf =
> red_char_device_write_buffer_get(state->priv->chardev,
> +
> client,
> +
> size);
> + if (!state->priv->recv_from_client_buf) {
> spice_error("failed to allocate write buffer");
> return NULL;
> }
> - return state->recv_from_client_buf->buf;
> + return state->priv->recv_from_client_buf->buf;
>
> default:
> return spice_malloc(size);
> @@ -463,7 +667,8 @@ static void
> spicevmc_red_channel_release_msg_rcv_buf(RedChannelClient *rcc,
> switch (type) {
> case SPICE_MSGC_SPICEVMC_DATA:
> /* buffer wasn't pushed to device */
> - red_char_device_write_buffer_release(state->chardev, &state-
> >recv_from_client_buf);
> + red_char_device_write_buffer_release(state->priv->chardev,
> + &state->priv-
> >recv_from_client_buf);
> break;
> default:
> free(msg);
> @@ -502,7 +707,7 @@ static void
> spicevmc_red_channel_send_migrate_data(RedChannelClient *rcc,
> spice_marshaller_add_uint32(m,
> SPICE_MIGRATE_DATA_SPICEVMC_MAGIC);
> spice_marshaller_add_uint32(m,
> SPICE_MIGRATE_DATA_SPICEVMC_VERSION);
>
> - red_char_device_migrate_data_marshall(state->chardev, m);
> + red_char_device_migrate_data_marshall(state->priv->chardev, m);
> }
>
> static void spicevmc_red_channel_send_port_init(RedChannelClient
> *rcc,
> @@ -556,6 +761,63 @@ static void
> spicevmc_red_channel_send_item(RedChannelClient *rcc,
> red_channel_client_begin_send_message(rcc);
> }
>
> +
> +static void
> +spice_vmc_state_class_init(SpiceVmcStateClass *klass)
> +{
> + GObjectClass *object_class = G_OBJECT_CLASS(klass);
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + g_type_class_add_private(klass, sizeof(SpiceVmcStatePrivate));
> +
> + object_class->get_property = spice_vmc_state_get_property;
> + object_class->set_property = spice_vmc_state_set_property;
> + object_class->constructed = spice_vmc_state_constructed;
> +
> + channel_class->handle_parsed =
> spicevmc_red_channel_client_handle_message_parsed;
> +
> + channel_class->config_socket =
> spicevmc_red_channel_client_config_socket;
> + channel_class->on_disconnect =
> spicevmc_red_channel_client_on_disconnect;
> + channel_class->send_item = spicevmc_red_channel_send_item;
> + channel_class->alloc_recv_buf =
> spicevmc_red_channel_alloc_msg_rcv_buf;
> + channel_class->release_recv_buf =
> spicevmc_red_channel_release_msg_rcv_buf;
> + channel_class->handle_migrate_flush_mark =
> spicevmc_channel_client_handle_migrate_flush_mark;
> + channel_class->handle_migrate_data =
> spicevmc_channel_client_handle_migrate_data;
> +
> + g_object_class_install_property(object_class,
> + PROP_DEVICE_INSTANCE,
> + g_param_spec_pointer("device-
> instance",
> + "device
> instance",
> + "Device
> instance for this channel",
> + G_PARAM_REA
> DWRITE |
> + G_PARAM_CON
> STRUCT_ONLY |
> + G_PARAM_STA
> TIC_STRINGS));
> +}
> +
> +static void
> +spice_vmc_state_usbredir_class_init(SpiceVmcStateUsbredirClass
> *klass)
> +{
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + channel_class->parser =
> spice_get_client_channel_parser(SPICE_CHANNEL_USBREDIR, NULL);
> +}
> +
> +static void
> +spice_vmc_state_webdav_class_init(SpiceVmcStateWebdavClass *klass)
> +{
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + channel_class->parser =
> spice_get_client_channel_parser(SPICE_CHANNEL_WEBDAV, NULL);
> +}
> +
> +static void
> +spice_vmc_state_port_class_init(SpiceVmcStatePortClass *klass)
> +{
> + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
> +
> + channel_class->parser =
> spice_get_client_channel_parser(SPICE_CHANNEL_PORT, NULL);
> +}
> +
> static void spicevmc_connect(RedChannel *channel, RedClient *client,
> RedsStream *stream, int migration, int num_common_caps,
> uint32_t *common_caps, int num_caps, uint32_t *caps)
> @@ -564,13 +826,15 @@ static void spicevmc_connect(RedChannel
> *channel, RedClient *client,
> SpiceVmcState *state;
> SpiceCharDeviceInstance *sin;
> SpiceCharDeviceInterface *sif;
> + uint32_t type, id;
>
> - state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel);
> - sin = state->chardev_sin;
> + state = SPICE_VMC_STATE(channel);
> + sin = state->priv->chardev_sin;
> + g_object_get(channel, "channel-type", &type, "id", &id, NULL);
>
> - if (state->rcc) {
> + if (state->priv->rcc) {
> spice_printerr("channel client %d:%d (%p) already connected,
> refusing second connection",
> - channel->type, channel->id, state->rcc);
> + type, id, state->priv->rcc);
> // TODO: notify client in advance about the in use channel
> using
> // SPICE_MSG_MAIN_CHANNEL_IN_USE (for example)
> reds_stream_free(stream);
> @@ -582,21 +846,21 @@ static void spicevmc_connect(RedChannel
> *channel, RedClient *client,
> if (!rcc) {
> return;
> }
> - state->rcc = rcc;
> + state->priv->rcc = rcc;
> red_channel_client_ack_zero_messages_window(rcc);
>
> if (strcmp(sin->subtype, "port") == 0) {
> spicevmc_port_send_init(rcc);
> }
>
> - if (!red_char_device_client_add(state->chardev, client, FALSE,
> 0, ~0, ~0,
> + if (!red_char_device_client_add(state->priv->chardev, client,
> FALSE, 0, ~0, ~0,
> red_channel_client_is_waiting_fo
> r_migrate_data(rcc))) {
> spice_warning("failed to add client to spicevmc");
> red_channel_client_disconnect(rcc);
> return;
> }
>
> - sif = spice_char_device_get_interface(state->chardev_sin);
> + sif = spice_char_device_get_interface(state->priv->chardev_sin);
> if (sif->state) {
> sif->state(sin, 1);
> }
> @@ -606,39 +870,9 @@ RedCharDevice *spicevmc_device_connect(RedsState
> *reds,
> SpiceCharDeviceInstance *sin,
> uint8_t channel_type)
> {
> - static uint8_t id[256] = { 0, };
> - SpiceVmcState *state;
> - ChannelCbs channel_cbs = { NULL, };
> - ClientCbs client_cbs = { NULL, };
> + SpiceVmcState *state = spice_vmc_state_new(reds, channel_type,
> sin);
>
> - channel_cbs.config_socket =
> spicevmc_red_channel_client_config_socket;
> - channel_cbs.on_disconnect =
> spicevmc_red_channel_client_on_disconnect;
> - channel_cbs.send_item = spicevmc_red_channel_send_item;
> - channel_cbs.alloc_recv_buf =
> spicevmc_red_channel_alloc_msg_rcv_buf;
> - channel_cbs.release_recv_buf =
> spicevmc_red_channel_release_msg_rcv_buf;
> - channel_cbs.handle_migrate_flush_mark =
> spicevmc_channel_client_handle_migrate_flush_mark;
> - channel_cbs.handle_migrate_data =
> spicevmc_channel_client_handle_migrate_data;
> -
> - state =
> (SpiceVmcState*)red_channel_create_parser(sizeof(SpiceVmcState),
> reds,
> - reds_get_core_interface(reds),
> channel_type, id[channel_type]++,
> - FALSE /* handle_acks */,
> - spice_get_client_channel_parser(c
> hannel_type, NULL),
> - spicevmc_red_channel_client_handl
> e_message_parsed,
> - &channel_cbs,
> - SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER);
> - red_channel_init_outgoing_messages_window(&state->channel);
> -
> - client_cbs.connect = spicevmc_connect;
> - red_channel_register_client_cbs(&state->channel, &client_cbs,
> NULL);
> -#ifdef USE_LZ4
> - red_channel_set_cap(&state->channel,
> SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4);
> -#endif
> -
> - state->chardev = red_char_device_spicevmc_new(sin, reds, state);
> - state->chardev_sin = sin;
> -
> - reds_register_channel(reds, &state->channel);
> - return state->chardev;
> + return state->priv->chardev;
> }
>
> /* Must be called from RedClient handling thread. */
> @@ -649,16 +883,16 @@ void spicevmc_device_disconnect(RedsState
> *reds, SpiceCharDeviceInstance *sin)
> /* FIXME */
> state = (SpiceVmcState
> *)red_char_device_opaque_get((RedCharDevice*)sin->st);
>
> - red_char_device_write_buffer_release(state->chardev, &state-
> >recv_from_client_buf);
> -
> + red_char_device_write_buffer_release(state->priv->chardev,
> + &state->priv-
> >recv_from_client_buf);
> /* FIXME */
> red_char_device_destroy((RedCharDevice*)sin->st);
> - state->chardev = NULL;
> + state->priv->chardev = NULL;
> sin->st = NULL;
>
> - reds_unregister_channel(reds, &state->channel);
> - free(state->pipe_item);
> - red_channel_destroy(&state->channel);
> + reds_unregister_channel(reds, RED_CHANNEL(state));
> + free(state->priv->pipe_item);
> + red_channel_destroy(RED_CHANNEL(state));
> }
>
> SPICE_GNUC_VISIBLE void
> spice_server_port_event(SpiceCharDeviceInstance *sin, uint8_t event)
> @@ -673,16 +907,16 @@ SPICE_GNUC_VISIBLE void
> spice_server_port_event(SpiceCharDeviceInstance *sin, ui
> /* FIXME */
> state = (SpiceVmcState
> *)red_char_device_opaque_get((RedCharDevice*)sin->st);
> if (event == SPICE_PORT_EVENT_OPENED) {
> - state->port_opened = TRUE;
> + state->priv->port_opened = TRUE;
> } else if (event == SPICE_PORT_EVENT_CLOSED) {
> - state->port_opened = FALSE;
> + state->priv->port_opened = FALSE;
> }
>
> - if (state->rcc == NULL) {
> + if (state->priv->rcc == NULL) {
> return;
> }
>
> - spicevmc_port_send_event(state->rcc, event);
> + spicevmc_port_send_event(state->priv->rcc, event);
> }
>
> static void
> diff --git a/server/stream.c b/server/stream.c
> index 6533111..4e70222 100644
> --- a/server/stream.c
> +++ b/server/stream.c
> @@ -19,7 +19,7 @@
> #endif
>
> #include "stream.h"
> -#include "display-channel.h"
> +#include "display-channel-private.h"
> #include "main-channel-client.h"
>
> #define FPS_TEST_INTERVAL 1
> @@ -198,7 +198,7 @@ static void update_copy_graduality(DisplayChannel
> *display, Drawable *drawable)
> SpiceBitmap *bitmap;
> spice_return_if_fail(drawable->red_drawable->type ==
> QXL_DRAW_COPY);
>
> - if (display->priv->stream_video != SPICE_STREAM_VIDEO_FILTER) {
> + if (display_channel_get_stream_video(display) !=
> SPICE_STREAM_VIDEO_FILTER) {
> drawable->copy_bitmap_graduality = BITMAP_GRADUAL_INVALID;
> return;
> }
More information about the Spice-devel
mailing list