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@xxxxxxxxxx> > > --- > 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; > } _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel