A patch of this size cannot be accepted, no matter how good it is. We need to find a way to split it. Any proposal would be good. Frediano > > When using private structs with GObject, there's a maximum size of (I > think) 64k, which was exceeded by the DisplayChannel object. To make > this work, I had to make several of the arrays here dynamically > allocated rather than statically allocated. > --- > server/Makefile.am | 5 + > server/common-graphics-channel-client.c | 3 +- > server/common-graphics-channel-client.h | 3 +- > server/common-graphics-channel.c | 181 ++++++++ > server/common-graphics-channel.h | 98 +++++ > server/cursor-channel.c | 126 +++--- > server/cursor-channel.h | 37 +- > server/dcc-send.c | 44 +- > server/dcc.c | 61 +-- > server/dcc.h | 4 +- > server/display-channel-private.h | 81 ++++ > server/display-channel.c | 726 > ++++++++++++++++++++------------ > server/display-channel.h | 158 +++---- > server/dummy-channel-client.c | 17 +- > server/dummy-channel.c | 58 +++ > server/dummy-channel.h | 61 +++ > server/inputs-channel.c | 262 +++++++----- > server/inputs-channel.h | 30 ++ > server/main-channel-client.c | 47 +-- > server/main-channel-client.h | 4 +- > server/main-channel.c | 241 ++++++----- > server/main-channel.h | 44 +- > server/red-channel-client-private.h | 19 + > server/red-channel-client.c | 197 +++++---- > server/red-channel-client.h | 6 +- > server/red-channel.c | 684 ++++++++++++++++++++---------- > server/red-channel.h | 190 ++++----- > server/red-parse-qxl.h | 2 + > server/red-qxl.c | 21 +- > server/red-replay-qxl.c | 2 +- > server/red-worker.c | 197 ++------- > server/red-worker.h | 64 --- > server/reds-private.h | 3 +- > server/reds.c | 67 +-- > server/smartcard.c | 131 ++++-- > server/sound.c | 43 +- > server/spicevmc.c | 339 ++++++++++----- > server/stream.c | 67 +-- > server/stream.h | 3 - > 39 files changed, 2753 insertions(+), 1573 deletions(-) > create mode 100644 server/common-graphics-channel.c > create mode 100644 server/common-graphics-channel.h > create mode 100644 server/display-channel-private.h > create mode 100644 server/dummy-channel.c > create mode 100644 server/dummy-channel.h > > diff --git a/server/Makefile.am b/server/Makefile.am > index b1de055..2679082 100644 > --- a/server/Makefile.am > +++ b/server/Makefile.am > @@ -73,6 +73,8 @@ libserver_la_SOURCES = \ > cache-item.h \ > char-device.c \ > char-device.h \ > + common-graphics-channel.c \ > + common-graphics-channel.h \ > common-graphics-channel-client.c \ > common-graphics-channel-client.h \ > common-graphics-channel-client-private.h \ > @@ -102,6 +104,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 \ > @@ -124,6 +128,7 @@ libserver_la_SOURCES = \ > red-worker.h \ > display-channel.c \ > display-channel.h \ > + display-channel-private.h \ > cursor-channel-client.c \ > cursor-channel-client.h \ > cursor-channel.c \ > diff --git a/server/common-graphics-channel-client.c > b/server/common-graphics-channel-client.c > index e83855b..6277d0b 100644 > --- a/server/common-graphics-channel-client.c > +++ b/server/common-graphics-channel-client.c > @@ -19,6 +19,7 @@ > #endif > > #include "common-graphics-channel-client-private.h" > +#include "common-graphics-channel.h" > #include "dcc.h" > #include "red-channel-client.h" > > @@ -89,7 +90,7 @@ static void > common_graphics_channel_client_constructed(GObject *object) > self->priv->is_low_bandwidth ? > WIDE_CLIENT_ACK_WINDOW : > NARROW_CLIENT_ACK_WINDOW); > > - channel->during_target_migrate = self->priv->migration_target; > + common_graphics_channel_set_during_target_migrate(channel, > self->priv->migration_target); > } > > static void > common_graphics_channel_client_class_init(CommonGraphicsChannelClientClass > *klass) > diff --git a/server/common-graphics-channel-client.h > b/server/common-graphics-channel-client.h > index dc1173a..7acb3a2 100644 > --- a/server/common-graphics-channel-client.h > +++ b/server/common-graphics-channel-client.h > @@ -21,6 +21,8 @@ > #include "red-common.h" > #include "red-channel-client.h" > > +#define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30) > + > G_BEGIN_DECLS > > #define TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT > common_graphics_channel_client_get_type() > @@ -49,7 +51,6 @@ struct CommonGraphicsChannelClientClass > > GType common_graphics_channel_client_get_type(void) G_GNUC_CONST; > > -typedef struct CommonGraphicsChannel CommonGraphicsChannel; > typedef struct RedClient RedClient; > typedef struct RedsStream RedsStream; > > diff --git a/server/common-graphics-channel.c > b/server/common-graphics-channel.c > new file mode 100644 > index 0000000..fe211aa > --- /dev/null > +++ b/server/common-graphics-channel.c > @@ -0,0 +1,181 @@ > +/* common-graphics-channel.c */ > +#ifdef HAVE_CONFIG_H > +#include <config.h> > +#endif > + > +#include <fcntl.h> > +#include <sys/socket.h> > +#include <netinet/in.h> > +#include <netinet/tcp.h> > + > +#include "common-graphics-channel.h" > +#include "common-graphics-channel-client.h" > + > +#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; > + uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE]; > + uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme. > + int during_target_migrate; /* TRUE when the client that is associated > with the channel > + is during migration. Turned off when the > vm is started. > + The flag is used to avoid sending messages > that are artifacts > + of the transition from stopped vm to > loaded vm (e.g., recreation > + of the primary surface) */ > +}; > + > +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); > + } > +} > + > +static int common_channel_config_socket(RedChannelClient *rcc) > +{ > + RedClient *client = red_channel_client_get_client(rcc); > + MainChannelClient *mcc = red_client_get_main(client); > + RedsStream *stream = red_channel_client_get_stream(rcc); > + CommonGraphicsChannelClient *ccc = COMMON_GRAPHICS_CHANNEL_CLIENT(rcc); > + int flags; > + int delay_val; > + gboolean low_bw; > + > + if ((flags = fcntl(stream->socket, F_GETFL)) == -1) { > + spice_warning("accept failed, %s", strerror(errno)); > + return FALSE; > + } > + > + if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) { > + spice_warning("accept failed, %s", strerror(errno)); > + return FALSE; > + } > + > + // TODO - this should be dynamic, not one time at channel creation > + low_bw = main_channel_client_is_low_bandwidth(mcc); > + common_graphics_channel_client_set_low_bandwidth(ccc, low_bw); > + delay_val = low_bw ? 0 : 1; > + /* FIXME: Using Nagle's Algorithm can lead to apparent delays, depending > + * on the delayed ack timeout on the other side. > + * Instead of using Nagle's, we need to implement message buffering on > + * the application level. > + * see: http://www.stuartcheshire.org/papers/NagleDelayedAck/ > + */ > + if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, > + sizeof(delay_val)) == -1) { > + if (errno != ENOTSUP) { > + spice_warning("setsockopt failed, %s", strerror(errno)); > + } > + } > + return TRUE; > +} > + > +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 = COMMON_GRAPHICS_CHANNEL(channel); > + > + /* SPICE_MSGC_MIGRATE_DATA is the only client message whose size is > dynamic */ > + if (type == SPICE_MSGC_MIGRATE_DATA) { > + return spice_malloc(size); > + } > + > + if (size > CHANNEL_RECEIVE_BUF_SIZE) { > + spice_critical("unexpected message size %u (max is %d)", size, > CHANNEL_RECEIVE_BUF_SIZE); > + return NULL; > + } > + return common->priv->recv_buf; > +} > + > +static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, > uint32_t size, > + uint8_t* msg) > +{ > + if (type == SPICE_MSGC_MIGRATE_DATA) { > + free(msg); > + } > +} > + > +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", > + "QXLInstance for > this channel", > + G_PARAM_READWRITE | > + > G_PARAM_CONSTRUCT_ONLY > | > + > G_PARAM_STATIC_STRINGS)); > +} > + > +static void > +common_graphics_channel_init(CommonGraphicsChannel *self) > +{ > + self->priv = GRAPHICS_CHANNEL_PRIVATE(self); > +} > + > +void common_graphics_channel_set_during_target_migrate(CommonGraphicsChannel > *self, gboolean value) > +{ > + self->priv->during_target_migrate = value; > +} > + > +gboolean > common_graphics_channel_get_during_target_migrate(CommonGraphicsChannel > *self) > +{ > + return self->priv->during_target_migrate; > +} > + > +QXLInstance* common_graphics_channel_get_qxl(CommonGraphicsChannel *self) > +{ > + return self->priv->qxl; > +} > diff --git a/server/common-graphics-channel.h > b/server/common-graphics-channel.h > new file mode 100644 > index 0000000..949470e > --- /dev/null > +++ b/server/common-graphics-channel.h > @@ -0,0 +1,98 @@ > +/* common-graphics-channel.h */ > +/* > + Copyright (C) 2009 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 __COMMON_GRAPHICS_CHANNEL_H__ > +#define __COMMON_GRAPHICS_CHANNEL_H__ > + > +#include <glib-object.h> > + > +#include "red-channel.h" > + > +G_BEGIN_DECLS > + > +#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; > + > +struct CommonGraphicsChannel > +{ > + RedChannel parent; > + > + CommonGraphicsChannelPrivate *priv; > +}; > + > +struct CommonGraphicsChannelClass > +{ > + RedChannelClass parent_class; > +}; > + > +GType common_graphics_channel_get_type(void) G_GNUC_CONST; > + > +void common_graphics_channel_set_during_target_migrate(CommonGraphicsChannel > *self, gboolean value); > +gboolean > common_graphics_channel_get_during_target_migrate(CommonGraphicsChannel > *self); > +QXLInstance* common_graphics_channel_get_qxl(CommonGraphicsChannel *self); > + > +enum { > + RED_PIPE_ITEM_TYPE_VERB = RED_PIPE_ITEM_TYPE_CHANNEL_BASE, > + RED_PIPE_ITEM_TYPE_INVAL_ONE, > + > + RED_PIPE_ITEM_TYPE_COMMON_LAST > +}; > + > +typedef struct RedVerbItem { > + RedPipeItem base; > + uint16_t verb; > +} RedVerbItem; > + > +static inline void red_marshall_verb(RedChannelClient *rcc, RedVerbItem > *item) > +{ > + red_channel_client_init_send_data(rcc, item->verb, NULL); > +} > + > +static inline void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb) > +{ > + RedVerbItem *item = spice_new(RedVerbItem, 1); > + > + red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_VERB); > + item->verb = verb; > + red_channel_client_pipe_add(rcc, &item->base); > +} > + > +static inline void red_pipe_add_verb_proxy(RedChannelClient *rcc, gpointer > data) > +{ > + uint16_t verb = GPOINTER_TO_UINT(data); > + red_pipe_add_verb(rcc, verb); > +} > + > +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)); > +} > + > + > +G_END_DECLS > + > +#endif /* __COMMON_GRAPHICS_CHANNEL_H__ */ > diff --git a/server/cursor-channel.c b/server/cursor-channel.c > index 032a1e1..26c72d8 100644 > --- a/server/cursor-channel.c > +++ b/server/cursor-channel.c > @@ -24,6 +24,7 @@ > #include "common-graphics-channel-client-private.h" > #include "cursor-channel.h" > #include "reds.h" > +#include "red-qxl.h" > > enum { > RED_PIPE_ITEM_TYPE_CURSOR = RED_PIPE_ITEM_TYPE_COMMON_LAST, > @@ -45,9 +46,12 @@ typedef struct RedCursorPipeItem { > int refs; > } RedCursorPipeItem; > > -struct CursorChannel { > - CommonGraphicsChannel common; // Must be the first thing > +G_DEFINE_TYPE(CursorChannel, cursor_channel, TYPE_COMMON_GRAPHICS_CHANNEL) > > +#define CURSOR_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), > TYPE_CURSOR_CHANNEL, CursorChannelPrivate)) > + > +struct CursorChannelPrivate > +{ > CursorItem *item; > int cursor_visible; > SpicePoint16 cursor_position; > @@ -104,10 +108,10 @@ static void cursor_item_unref(CursorItem *item) > > static void cursor_set_item(CursorChannel *cursor, CursorItem *item) > { > - if (cursor->item) > - cursor_item_unref(cursor->item); > + if (cursor->priv->item) > + cursor_item_unref(cursor->priv->item); > > - cursor->item = item ? cursor_item_ref(item) : NULL; > + cursor->priv->item = item ? cursor_item_ref(item) : NULL; > } > > static RedPipeItem *new_cursor_pipe_item(RedChannelClient *rcc, void *data, > int num) > @@ -237,12 +241,12 @@ static void red_marshall_cursor_init(RedChannelClient > *rcc, SpiceMarshaller *bas > cursor_channel = (CursorChannel*)red_channel_client_get_channel(rcc); > > red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INIT, NULL); > - 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; > + 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; > > - cursor_fill(ccc, &msg.cursor, cursor_channel->item, &info); > + cursor_fill(ccc, &msg.cursor, cursor_channel->priv->item, &info); > spice_marshall_msg_cursor_init(base_marshaller, &msg); > add_buf_from_info(base_marshaller, &info); > } > @@ -251,8 +255,7 @@ static void cursor_marshall(RedChannelClient *rcc, > SpiceMarshaller *m, > RedCursorPipeItem *cursor_pipe_item) > { > - 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)); > CursorChannelClient *ccc = CURSOR_CHANNEL_CLIENT(rcc); > CursorItem *item = cursor_pipe_item->cursor_item; > RedPipeItem *pipe_item = &cursor_pipe_item->base; > @@ -277,7 +280,7 @@ static void cursor_marshall(RedChannelClient *rcc, > > 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->cursor_visible; > + cursor_set.visible = cursor_channel->priv->cursor_visible; > > cursor_fill(ccc, &cursor_set.cursor, item, &info); > spice_marshall_msg_cursor_set(m, &cursor_set); > @@ -378,27 +381,17 @@ static void > cursor_channel_release_item(RedChannelClient *rcc, RedPipeItem *item > } > } > > -CursorChannel* cursor_channel_new(RedWorker *worker) > +CursorChannel* cursor_channel_new(SpiceServer *reds, 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, > - .hold_item = cursor_channel_hold_pipe_item, > - .release_item = cursor_channel_release_item > - }; > - > spice_info("create cursor channel"); > - channel = red_worker_new_channel(worker, sizeof(CursorChannel), > "cursor_channel", > - SPICE_CHANNEL_CURSOR, 0, > - &cbs, > red_channel_client_handle_message); > - > - cursor_channel = (CursorChannel *)channel; > - cursor_channel->cursor_visible = TRUE; > - cursor_channel->mouse_mode = SPICE_MOUSE_MODE_SERVER; > - > - return cursor_channel; > + return g_object_new(TYPE_CURSOR_CHANNEL, > + "spice-server", reds, > + "core-interface", core, > + "channel-type", SPICE_CHANNEL_CURSOR, > + "migration-flags", 0, > + "qxl", qxl, > + NULL); > } > > void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd > *cursor_cmd) > @@ -409,35 +402,36 @@ void cursor_channel_process_cmd(CursorChannel *cursor, > RedCursorCmd *cursor_cmd) > spice_return_if_fail(cursor); > spice_return_if_fail(cursor_cmd); > > - cursor_item = cursor_item_new(cursor->common.qxl, cursor_cmd); > + cursor_item = > cursor_item_new(common_graphics_channel_get_qxl(COMMON_GRAPHICS_CHANNEL(cursor)), > + cursor_cmd); > > switch (cursor_cmd->type) { > case QXL_CURSOR_SET: > - cursor->cursor_visible = cursor_cmd->u.set.visible; > + cursor->priv->cursor_visible = cursor_cmd->u.set.visible; > cursor_set_item(cursor, cursor_item); > break; > case QXL_CURSOR_MOVE: > - cursor_show = !cursor->cursor_visible; > - cursor->cursor_visible = TRUE; > - cursor->cursor_position = cursor_cmd->u.position; > + cursor_show = !cursor->priv->cursor_visible; > + cursor->priv->cursor_visible = TRUE; > + cursor->priv->cursor_position = cursor_cmd->u.position; > break; > case QXL_CURSOR_HIDE: > - cursor->cursor_visible = FALSE; > + cursor->priv->cursor_visible = FALSE; > break; > case QXL_CURSOR_TRAIL: > - cursor->cursor_trail_length = cursor_cmd->u.trail.length; > - cursor->cursor_trail_frequency = cursor_cmd->u.trail.frequency; > + cursor->priv->cursor_trail_length = cursor_cmd->u.trail.length; > + cursor->priv->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->mouse_mode == SPICE_MOUSE_MODE_SERVER > + if (red_channel_is_connected(RED_CHANNEL(cursor)) && > + (cursor->priv->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); > } > > @@ -446,34 +440,34 @@ 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->cursor_visible = TRUE; > - cursor->cursor_position.x = cursor->cursor_position.y = 0; > - cursor->cursor_trail_length = cursor->cursor_trail_frequency = 0; > + 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; > > if (red_channel_is_connected(channel)) { > red_channel_pipes_add_type(channel, > RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE); > - if (!cursor->common.during_target_migrate) { > + if > (!common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(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(RED_CHANNEL(cursor), > COMMON_CLIENT_TIMEOUT)) { > - red_channel_apply_clients(channel, > + red_channel_apply_clients(RED_CHANNEL(cursor), > red_channel_client_disconnect_if_pending_send); > } > } > } > > -void cursor_channel_init(CursorChannel *cursor, CursorChannelClient *client) > +void cursor_channel_do_init(CursorChannel *cursor, CursorChannelClient > *client) > { > spice_return_if_fail(cursor); > > - if (!red_channel_is_connected(&cursor->common.base) > - || COMMON_GRAPHICS_CHANNEL(cursor)->during_target_migrate) { > + if (!red_channel_is_connected(RED_CHANNEL(cursor)) > + || > common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(cursor))) > { > spice_debug("during_target_migrate: skip init"); > return; > } > @@ -489,5 +483,29 @@ void cursor_channel_set_mouse_mode(CursorChannel > *cursor, uint32_t mode) > { > spice_return_if_fail(cursor); > > - cursor->mouse_mode = mode; > + cursor->priv->mouse_mode = mode; > +} > + > +static void > +cursor_channel_class_init(CursorChannelClass *klass) > +{ > + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass); > + > + g_type_class_add_private(klass, sizeof(CursorChannelPrivate)); > + > + 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; > + channel_class->hold_item = cursor_channel_hold_pipe_item; > + channel_class->release_item = cursor_channel_release_item; > +} > + > +static void > +cursor_channel_init(CursorChannel *self) > +{ > + self->priv = CURSOR_CHANNEL_PRIVATE(self); > + self->priv->cursor_visible = TRUE; > + self->priv->mouse_mode = SPICE_MOUSE_MODE_SERVER; > } > diff --git a/server/cursor-channel.h b/server/cursor-channel.h > index 2b09b21..81ad96f 100644 > --- a/server/cursor-channel.h > +++ b/server/cursor-channel.h > @@ -19,16 +19,47 @@ > # define CURSOR_CHANNEL_H_ > > #include "cursor-channel-client.h" > -#include "red-worker.h" > +#include "common-graphics-channel.h" > +#include "red-parse-qxl.h" > + > +G_BEGIN_DECLS > + > +#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)) > > typedef struct CursorChannel CursorChannel; > +typedef struct CursorChannelClass CursorChannelClass; > +typedef struct CursorChannelPrivate CursorChannelPrivate; > + > +struct CursorChannel > +{ > + CommonGraphicsChannel parent; > + > + CursorChannelPrivate *priv; > +}; > + > +struct CursorChannelClass > +{ > + CommonGraphicsChannelClass parent_class; > +}; > + > +GType cursor_channel_get_type(void) G_GNUC_CONST; > + > typedef struct CursorItem CursorItem; > > -CursorChannel* cursor_channel_new (RedWorker *worker); > +CursorChannel* cursor_channel_new (SpiceServer *reds, > QXLInstance *qxl, > + const > SpiceCoreInterfaceInternal *core); > void cursor_channel_disconnect (CursorChannel > *cursor_channel); > void cursor_channel_reset (CursorChannel *cursor); > -void cursor_channel_init (CursorChannel *cursor, > CursorChannelClient* client); > +void cursor_channel_do_init (CursorChannel *cursor, > CursorChannelClient* client); > void cursor_channel_process_cmd (CursorChannel *cursor, > RedCursorCmd *cursor_cmd); > void cursor_channel_set_mouse_mode(CursorChannel *cursor, > uint32_t mode); > > +G_END_DECLS > + > #endif /* CURSOR_CHANNEL_H_ */ > diff --git a/server/dcc-send.c b/server/dcc-send.c > index 2525753..9b9af93 100644 > --- a/server/dcc-send.c > +++ b/server/dcc-send.c > @@ -21,6 +21,7 @@ > > #include "dcc-private.h" > #include "display-channel.h" > +#include "display-channel-private.h" > > #include "common/marshaller.h" > #include "common/generated_server_marshallers.h" > @@ -94,9 +95,9 @@ static int is_surface_area_lossy(DisplayChannelClient *dcc, > uint32_t surface_id, > QRegion lossy_region; > DisplayChannel *display = DCC_TO_DC(dcc); > > - spice_return_val_if_fail(validate_surface(display, surface_id), FALSE); > + spice_return_val_if_fail(display_channel_validate_surface(display, > surface_id), FALSE); > > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > surface_lossy_region = > &dcc->priv->surface_client_lossy_region[surface_id]; > > if (!area) { > @@ -197,8 +198,7 @@ static void > red_display_add_image_to_pixmap_cache(RedChannelClient *rcc, > int is_lossy) > { > DisplayChannel *display_channel = > - SPICE_CONTAINEROF(red_channel_client_get_channel(rcc), > DisplayChannel, > - common.base); > + DISPLAY_CHANNEL(red_channel_client_get_channel(rcc)); > DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc); > > if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > @@ -210,13 +210,13 @@ static void > red_display_add_image_to_pixmap_cache(RedChannelClient *rcc, > io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME; > dcc->priv->send_data.pixmap_cache_items[dcc->priv->send_data.num_pixmap_cache_items++] > = > image->descriptor.id; > - stat_inc_counter(reds, > display_channel->add_to_cache_counter, 1); > + stat_inc_counter(reds, > display_channel->priv->add_to_cache_counter, 1); > } > } > } > > if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > - stat_inc_counter(reds, display_channel->non_cache_counter, 1); > + stat_inc_counter(reds, display_channel->priv->non_cache_counter, 1); > } > } > > @@ -367,7 +367,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, > SpiceMarshaller *m, > dcc->priv->send_data.pixmap_cache_items[dcc->priv->send_data.num_pixmap_cache_items++] > = > image.descriptor.id; > if (can_lossy || !lossy_cache_item) { > - if (!display->enable_jpeg || lossy_cache_item) { > + if (!display->priv->enable_jpeg || lossy_cache_item) { > image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE; > } else { > // making sure, in multiple monitor scenario, that lossy > items that > @@ -379,7 +379,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, > SpiceMarshaller *m, > &bitmap_palette_out, > &lzplt_palette_out); > spice_assert(bitmap_palette_out == NULL); > spice_assert(lzplt_palette_out == NULL); > - stat_inc_counter(reds, display->cache_hits_counter, 1); > + stat_inc_counter(reds, display->priv->cache_hits_counter, > 1); > pthread_mutex_unlock(&dcc->priv->pixmap_cache->lock); > return FILL_BITS_TYPE_CACHE; > } else { > @@ -396,13 +396,13 @@ static FillBitsType fill_bits(DisplayChannelClient > *dcc, SpiceMarshaller *m, > RedSurface *surface; > > surface_id = simage->u.surface.surface_id; > - if (!validate_surface(display, surface_id)) { > + if (!display_channel_validate_surface(display, surface_id)) { > spice_warning("Invalid surface in SPICE_IMAGE_TYPE_SURFACE"); > pthread_mutex_unlock(&dcc->priv->pixmap_cache->lock); > return FILL_BITS_TYPE_SURFACE; > } > > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE; > image.descriptor.flags = 0; > image.descriptor.width = surface->context.width; > @@ -1692,7 +1692,7 @@ static int red_marshall_stream_data(RedChannelClient > *rcc, > height = stream->height; > } > > - StreamAgent *agent = &dcc->priv->stream_agents[get_stream_id(display, > stream)]; > + StreamAgent *agent = > &dcc->priv->stream_agents[display_channel_get_stream_id(display, stream)]; > uint64_t time_now = spice_get_monotonic_time_ns(); > size_t outbuf_size; > > @@ -1739,7 +1739,7 @@ static int red_marshall_stream_data(RedChannelClient > *rcc, > > red_channel_client_init_send_data(rcc, > SPICE_MSG_DISPLAY_STREAM_DATA, NULL); > > - stream_data.base.id = get_stream_id(display, stream); > + stream_data.base.id = display_channel_get_stream_id(display, > stream); > stream_data.base.multi_media_time = frame_mm_time; > stream_data.data_size = n; > > @@ -1749,7 +1749,7 @@ static int red_marshall_stream_data(RedChannelClient > *rcc, > > red_channel_client_init_send_data(rcc, > SPICE_MSG_DISPLAY_STREAM_DATA_SIZED, NULL); > > - stream_data.base.id = get_stream_id(display, stream); > + stream_data.base.id = display_channel_get_stream_id(display, > stream); > stream_data.base.multi_media_time = frame_mm_time; > stream_data.data_size = n; > stream_data.width = width; > @@ -1822,8 +1822,7 @@ static void > display_channel_marshall_migrate_data(RedChannelClient *rcc, > DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc); > SpiceMigrateDataDisplay display_data = {0,}; > > - display_channel = SPICE_CONTAINEROF(red_channel_client_get_channel(rcc), > - DisplayChannel, common.base); > + 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); > @@ -1853,7 +1852,7 @@ static void > display_channel_marshall_migrate_data(RedChannelClient *rcc, > spice_marshaller_add(base_marshaller, > (uint8_t *)&display_data, sizeof(display_data) - > sizeof(uint32_t)); > display_channel_marshall_migrate_data_surfaces(dcc, base_marshaller, > - > display_channel->enable_jpeg); > + > display_channel->priv->enable_jpeg); > } > > static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, > @@ -2132,8 +2131,7 @@ static void marshall_qxl_drawable(RedChannelClient > *rcc, > > Drawable *item = dpi->drawable; > DisplayChannel *display = > - SPICE_CONTAINEROF(red_channel_client_get_channel(rcc), > DisplayChannel, > - common.base); > + 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 > @@ -2141,7 +2139,7 @@ static void marshall_qxl_drawable(RedChannelClient > *rcc, > if ((item->stream || item->sized_stream) && > red_marshall_stream_data(rcc, m, item)) { > return; > } > - if (display->enable_jpeg) > + if (display->priv->enable_jpeg) > marshall_lossy_qxl_drawable(rcc, m, dpi); > else > marshall_lossless_qxl_drawable(rcc, m, dpi); > @@ -2160,7 +2158,7 @@ static void marshall_stream_start(RedChannelClient > *rcc, > SpiceClipRects clip_rects; > > stream_create.surface_id = 0; > - stream_create.id = get_stream_id(DCC_TO_DC(dcc), stream); > + stream_create.id = display_channel_get_stream_id(DCC_TO_DC(dcc), > stream); > stream_create.flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : > 0; > stream_create.codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG; > > @@ -2196,7 +2194,7 @@ static void marshall_stream_clip(RedChannelClient *rcc, > red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CLIP, > &item->base); > SpiceMsgDisplayStreamClip stream_clip; > > - stream_clip.id = get_stream_id(DCC_TO_DC(dcc), agent->stream); > + stream_clip.id = display_channel_get_stream_id(DCC_TO_DC(dcc), > agent->stream); > stream_clip.clip.type = item->clip_type; > stream_clip.clip.rects = item->rects; > > @@ -2210,7 +2208,7 @@ static void marshall_stream_end(RedChannelClient *rcc, > SpiceMsgDisplayStreamDestroy destroy; > > red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY, > NULL); > - destroy.id = get_stream_id(DCC_TO_DC(dcc), agent->stream); > + destroy.id = display_channel_get_stream_id(DCC_TO_DC(dcc), > agent->stream); > stream_agent_stop(agent); > spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy); > } > @@ -2319,7 +2317,7 @@ static void marshall_gl_scanout(RedChannelClient *rcc, > { > DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc); > DisplayChannel *display_channel = DCC_TO_DC(dcc); > - QXLInstance* qxl = display_channel->common.qxl; > + QXLInstance* qxl = > common_graphics_channel_get_qxl(COMMON_GRAPHICS_CHANNEL(display_channel)); > > SpiceMsgDisplayGlScanoutUnix *scanout = red_qxl_get_gl_scanout(qxl); > if (scanout != NULL) { > diff --git a/server/dcc.c b/server/dcc.c > index 6b5517e..d3c77f4 100644 > --- a/server/dcc.c > +++ b/server/dcc.c > @@ -22,6 +22,7 @@ > #include "dcc-private.h" > #include "dcc.h" > #include "display-channel.h" > +#include "display-channel-private.h" > #include "red-channel-client-private.h" > #include "spice-server-enums.h" > > @@ -305,12 +306,12 @@ void dcc_create_surface(DisplayChannelClient *dcc, int > surface_id) > flags = is_primary_surface(DCC_TO_DC(dcc), surface_id) ? > SPICE_SURFACE_FLAGS_PRIMARY : 0; > > /* don't send redundant create surface commands to client */ > - if (!dcc || display->common.during_target_migrate || > + if (!dcc || > common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(display)) > || > dcc->priv->surface_client_created[surface_id]) { > return; > } > channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(dcc)); > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > create = red_surface_create_item_new(channel, > surface_id, surface->context.width, > surface->context.height, > @@ -327,7 +328,7 @@ RedImageItem > *dcc_add_surface_area_image(DisplayChannelClient *dcc, > int can_lossy) > { > DisplayChannel *display = DCC_TO_DC(dcc); > - RedSurface *surface = &display->surfaces[surface_id]; > + RedSurface *surface = &display->priv->surfaces[surface_id]; > SpiceCanvas *canvas = surface->context.canvas; > RedImageItem *item; > int stride; > @@ -393,7 +394,7 @@ void dcc_push_surface_image(DisplayChannelClient *dcc, > int surface_id) > } > > display = DCC_TO_DC(dcc); > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > if (!surface->context.canvas) { > return; > } > @@ -495,7 +496,7 @@ static void dcc_init_stream_agents(DisplayChannelClient > *dcc) > dcc->priv->stream_agents = g_new0(StreamAgent, NUM_STREAMS); > for (i = 0; i < NUM_STREAMS; i++) { > StreamAgent *agent = &dcc->priv->stream_agents[i]; > - agent->stream = &display->streams_buf[i]; > + agent->stream = &display->priv->streams_buf[i]; > region_init(&agent->vis_region); > region_init(&agent->clip); > red_pipe_item_init(&agent->create_item, > RED_PIPE_ITEM_TYPE_STREAM_CREATE); > @@ -552,7 +553,7 @@ DisplayChannelClient *dcc_new(DisplayChannel *display, > > static void dcc_create_all_streams(DisplayChannelClient *dcc) > { > - Ring *ring = &DCC_TO_DC(dcc)->streams; > + Ring *ring = &DCC_TO_DC(dcc)->priv->streams; > RingItem *item = ring; > > while ((item = ring_next(ring, item))) { > @@ -606,7 +607,7 @@ void dcc_start(DisplayChannelClient *dcc) > return; > > red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc)); > - if (display->surfaces[0].context.canvas) { > + if (display->priv->surfaces[0].context.canvas) { > display_channel_current_flush(display, 0); > red_channel_client_pipe_add_type(rcc, > RED_PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE); > dcc_create_surface(dcc, 0); > @@ -693,7 +694,7 @@ static RedMonitorsConfigItem > *red_monitors_config_item_new(RedChannel* channel, > void dcc_push_monitors_config(DisplayChannelClient *dcc) > { > DisplayChannel *dc = DCC_TO_DC(dcc); > - MonitorsConfig *monitors_config = dc->monitors_config; > + MonitorsConfig *monitors_config = dc->priv->monitors_config; > RedMonitorsConfigItem *mci; > RedChannel *channel; > > @@ -709,7 +710,7 @@ void dcc_push_monitors_config(DisplayChannelClient *dcc) > > channel = red_channel_client_get_channel(RED_CHANNEL_CLIENT(dcc)); > mci = red_monitors_config_item_new(channel, > - > monitors_config_ref(dc->monitors_config)); > + > monitors_config_ref(dc->priv->monitors_config)); > red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &mci->pipe_item); > red_channel_client_push(RED_CHANNEL_CLIENT(dcc)); > } > @@ -777,7 +778,7 @@ void dcc_destroy_surface(DisplayChannelClient *dcc, > uint32_t surface_id) > display = DCC_TO_DC(dcc); > channel = RED_CHANNEL(display); > > - if (COMMON_GRAPHICS_CHANNEL(display)->during_target_migrate || > + if > (common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(display)) > || > !dcc->priv->surface_client_created[surface_id]) { > return; > } > @@ -859,7 +860,7 @@ static int dcc_compress_image_glz(DisplayChannelClient > *dcc, > { > DisplayChannel *display_channel = DCC_TO_DC(dcc); > stat_start_time_t start_time; > - stat_start_time_init(&start_time, &display_channel->zlib_glz_stat); > + stat_start_time_init(&start_time, > &display_channel->priv->zlib_glz_stat); > spice_assert(bitmap_fmt_is_rgb(src->format)); > GlzData *glz_data = &dcc->priv->glz_data; > ZlibData *zlib_data; > @@ -890,12 +891,12 @@ static int dcc_compress_image_glz(DisplayChannelClient > *dcc, > glz_drawable_instance, > &glz_drawable_instance->context); > > - stat_compress_add(&display_channel->glz_stat, start_time, src->stride * > src->y, glz_size); > + stat_compress_add(&display_channel->priv->glz_stat, start_time, > src->stride * src->y, glz_size); > > - if (!display_channel->enable_zlib_glz_wrap || (glz_size < > MIN_GLZ_SIZE_FOR_ZLIB)) { > + if (!display_channel->priv->enable_zlib_glz_wrap || (glz_size < > MIN_GLZ_SIZE_FOR_ZLIB)) { > goto glz; > } > - stat_start_time_init(&start_time, &display_channel->zlib_glz_stat); > + stat_start_time_init(&start_time, > &display_channel->priv->zlib_glz_stat); > zlib_data = &dcc->priv->zlib_data; > > encoder_data_init(&zlib_data->data, dcc); > @@ -922,7 +923,7 @@ static int dcc_compress_image_glz(DisplayChannelClient > *dcc, > o_comp_data->comp_buf = zlib_data->data.bufs_head; > o_comp_data->comp_buf_size = zlib_size; > > - stat_compress_add(&display_channel->zlib_glz_stat, start_time, glz_size, > zlib_size); > + stat_compress_add(&display_channel->priv->zlib_glz_stat, start_time, > glz_size, zlib_size); > return TRUE; > glz: > dest->descriptor.type = SPICE_IMAGE_TYPE_GLZ_RGB; > @@ -944,7 +945,7 @@ static int dcc_compress_image_lz(DisplayChannelClient > *dcc, > int size; // size of the compressed data > > stat_start_time_t start_time; > - stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->lz_stat); > + stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->priv->lz_stat); > > #ifdef COMPRESS_DEBUG > spice_info("LZ LOCAL compress"); > @@ -995,7 +996,7 @@ static int dcc_compress_image_lz(DisplayChannelClient > *dcc, > o_comp_data->lzplt_palette = dest->u.lz_plt.palette; > } > > - stat_compress_add(&DCC_TO_DC(dcc)->lz_stat, start_time, src->stride * > src->y, > + stat_compress_add(&DCC_TO_DC(dcc)->priv->lz_stat, start_time, > src->stride * src->y, > o_comp_data->comp_buf_size); > return TRUE; > } > @@ -1016,7 +1017,7 @@ static int dcc_compress_image_jpeg(DisplayChannelClient > *dcc, SpiceImage *dest, > int stride; > uint8_t *lz_out_start_byte; > stat_start_time_t start_time; > - stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->jpeg_alpha_stat); > + stat_start_time_init(&start_time, > &DCC_TO_DC(dcc)->priv->jpeg_alpha_stat); > > #ifdef COMPRESS_DEBUG > spice_info("JPEG compress"); > @@ -1080,7 +1081,7 @@ static int dcc_compress_image_jpeg(DisplayChannelClient > *dcc, SpiceImage *dest, > o_comp_data->comp_buf_size = jpeg_size; > o_comp_data->is_lossy = TRUE; > > - stat_compress_add(&DCC_TO_DC(dcc)->jpeg_stat, start_time, > src->stride * src->y, > + stat_compress_add(&DCC_TO_DC(dcc)->priv->jpeg_stat, start_time, > src->stride * src->y, > o_comp_data->comp_buf_size); > return TRUE; > } > @@ -1122,7 +1123,7 @@ static int dcc_compress_image_jpeg(DisplayChannelClient > *dcc, SpiceImage *dest, > o_comp_data->comp_buf = jpeg_data->data.bufs_head; > o_comp_data->comp_buf_size = jpeg_size + alpha_lz_size; > o_comp_data->is_lossy = TRUE; > - stat_compress_add(&DCC_TO_DC(dcc)->jpeg_alpha_stat, start_time, > src->stride * src->y, > + stat_compress_add(&DCC_TO_DC(dcc)->priv->jpeg_alpha_stat, start_time, > src->stride * src->y, > o_comp_data->comp_buf_size); > return TRUE; > } > @@ -1135,7 +1136,7 @@ static int dcc_compress_image_lz4(DisplayChannelClient > *dcc, SpiceImage *dest, > Lz4EncoderContext *lz4 = dcc->priv->lz4; > int lz4_size = 0; > stat_start_time_t start_time; > - stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->lz4_stat); > + stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->priv->lz4_stat); > > #ifdef COMPRESS_DEBUG > spice_info("LZ4 compress"); > @@ -1172,7 +1173,7 @@ static int dcc_compress_image_lz4(DisplayChannelClient > *dcc, SpiceImage *dest, > o_comp_data->comp_buf = lz4_data->data.bufs_head; > o_comp_data->comp_buf_size = lz4_size; > > - stat_compress_add(&DCC_TO_DC(dcc)->lz4_stat, start_time, src->stride * > src->y, > + stat_compress_add(&DCC_TO_DC(dcc)->priv->lz4_stat, start_time, > src->stride * src->y, > o_comp_data->comp_buf_size); > return TRUE; > } > @@ -1186,7 +1187,7 @@ static int dcc_compress_image_quic(DisplayChannelClient > *dcc, SpiceImage *dest, > volatile QuicImageType type; > int size, stride; > stat_start_time_t start_time; > - stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->quic_stat); > + stat_start_time_init(&start_time, &DCC_TO_DC(dcc)->priv->quic_stat); > > #ifdef COMPRESS_DEBUG > spice_info("QUIC compress"); > @@ -1246,7 +1247,7 @@ static int dcc_compress_image_quic(DisplayChannelClient > *dcc, SpiceImage *dest, > o_comp_data->comp_buf = quic_data->data.bufs_head; > o_comp_data->comp_buf_size = size << 2; > > - stat_compress_add(&DCC_TO_DC(dcc)->quic_stat, start_time, src->stride * > src->y, > + stat_compress_add(&DCC_TO_DC(dcc)->priv->quic_stat, start_time, > src->stride * src->y, > o_comp_data->comp_buf_size); > return TRUE; > } > @@ -1345,14 +1346,14 @@ int dcc_compress_image(DisplayChannelClient *dcc, > stat_start_time_t start_time; > int success = FALSE; > > - stat_start_time_init(&start_time, &display_channel->off_stat); > + stat_start_time_init(&start_time, &display_channel->priv->off_stat); > > image_compression = get_compression_for_bitmap(src, > dcc->priv->image_compression, drawable); > switch (image_compression) { > case SPICE_IMAGE_COMPRESSION_OFF: > break; > case SPICE_IMAGE_COMPRESSION_QUIC: > - if (can_lossy && display_channel->enable_jpeg && > + if (can_lossy && display_channel->priv->enable_jpeg && > (src->format != SPICE_BITMAP_FMT_RGBA || > !bitmap_has_extra_stride(src))) { > success = dcc_compress_image_jpeg(dcc, dest, src, o_comp_data); > break; > @@ -1392,7 +1393,7 @@ lz_compress: > > if (!success) { > uint64_t image_size = src->stride * src->y; > - stat_compress_add(&display_channel->off_stat, start_time, > image_size, image_size); > + stat_compress_add(&display_channel->priv->off_stat, start_time, > image_size, image_size); > } > > return success; > @@ -1739,15 +1740,15 @@ int dcc_handle_migrate_data(DisplayChannelClient > *dcc, uint32_t size, void *mess > if (migrate_data->low_bandwidth_setting) { > red_channel_client_ack_set_client_window(RED_CHANNEL_CLIENT(dcc), > WIDE_CLIENT_ACK_WINDOW); > if (dcc->priv->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) { > - display->enable_jpeg = TRUE; > + display->priv->enable_jpeg = TRUE; > } > if (dcc->priv->zlib_glz_state == SPICE_WAN_COMPRESSION_AUTO) { > - display->enable_zlib_glz_wrap = TRUE; > + display->priv->enable_zlib_glz_wrap = TRUE; > } > } > > surfaces = (uint8_t *)message + migrate_data->surfaces_at_client_ptr; > - surfaces_restored = display->enable_jpeg ? > + surfaces_restored = display->priv->enable_jpeg ? > restore_surfaces_lossy(dcc, (MigrateDisplaySurfacesAtClientLossy > *)surfaces) : > restore_surfaces_lossless(dcc, > (MigrateDisplaySurfacesAtClientLossless*)surfaces); > > diff --git a/server/dcc.h b/server/dcc.h > index 9567afd..ab51047 100644 > --- a/server/dcc.h > +++ b/server/dcc.h > @@ -21,7 +21,7 @@ > #include <glib-object.h> > #include "image-cache.h" > #include "pixmap-cache.h" > -#include "red-worker.h" > +#include "common-graphics-channel-client.h" > #include "display-limits.h" > > G_BEGIN_DECLS > @@ -69,7 +69,6 @@ GType display_channel_client_get_type(void) G_GNUC_CONST; > > #define MAX_PIPE_SIZE 50 > > -/* FIXME: remove */ > typedef struct DisplayChannel DisplayChannel; > typedef struct Stream Stream; > typedef struct StreamAgent StreamAgent; > @@ -87,7 +86,6 @@ typedef struct FreeList { > WaitForChannels wait; > } FreeList; > > -#define DCC_TO_WORKER(dcc) > ((RedWorker*)((CommonGraphicsChannel*)(red_channel_client_get_channel((RedChannelClient*)dcc)))->worker) > #define DCC_TO_DC(dcc) > ((DisplayChannel*)red_channel_client_get_channel((RedChannelClient*)dcc)) > > typedef struct RedSurfaceCreateItem { > diff --git a/server/display-channel-private.h > b/server/display-channel-private.h > new file mode 100644 > index 0000000..039a93d > --- /dev/null > +++ b/server/display-channel-private.h > @@ -0,0 +1,81 @@ > +/* > + 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_ > + > +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; > + _Drawable *free_drawables; > + > + int stream_video; > + uint32_t stream_count; > + Stream *streams_buf; > + Stream *free_streams; > + Ring streams; > + ItemTrace *items_trace; > + uint32_t next_item_trace; > + uint64_t streams_size_total; > + > + RedSurface *surfaces; > + uint32_t n_surfaces; > + SpiceImageSurfaces image_surfaces; > + > + ImageCache *image_cache; > + RedCompressBuf *free_compress_bufs; > + > + 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 > + stat_info_t off_stat; > + stat_info_t lz_stat; > + stat_info_t glz_stat; > + stat_info_t quic_stat; > + stat_info_t jpeg_stat; > + stat_info_t zlib_glz_stat; > + stat_info_t jpeg_alpha_stat; > + stat_info_t lz4_stat; > +}; > + > +#endif /* DISPLAY_CHANNEL_PRIVATE_H_ */ > diff --git a/server/display-channel.c b/server/display-channel.c > index 352058a..91b4255 100644 > --- a/server/display-channel.c > +++ b/server/display-channel.c > @@ -19,6 +19,138 @@ > #endif > > #include "display-channel.h" > +#include "display-channel-private.h" > + > +G_DEFINE_TYPE(DisplayChannel, display_channel, TYPE_COMMON_GRAPHICS_CHANNEL) > + > +#define DISPLAY_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), > TYPE_DISPLAY_CHANNEL, DisplayChannelPrivate)) > + > +enum { > + PROP0, > + PROP_N_SURFACES > +}; > + > +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); > + if (self->priv->surfaces == NULL) > + self->priv->surfaces = g_new0(RedSurface, > self->priv->n_surfaces); > + else > + self->priv->surfaces = g_renew(RedSurface, > self->priv->surfaces, self->priv->n_surfaces); > + 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->drawables); > + g_free(self->priv->surfaces); > + g_free(self->priv->streams_buf); > + g_free(self->priv->items_trace); > + g_free(self->priv->image_cache); > +} > + > +static void > +display_channel_constructed(GObject *object) > +{ > + DisplayChannel *self = DISPLAY_CHANNEL(object); > + > + G_OBJECT_CLASS(display_channel_parent_class)->constructed(object); > + > + 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); > +} > + > +static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, > uint32_t surface_id) > +{ > + DisplayChannelPrivate *p = SPICE_CONTAINEROF(surfaces, > DisplayChannelPrivate, image_surfaces); > + DisplayChannel *display = p->pub; > + > + spice_return_val_if_fail(display_channel_validate_surface(display, > surface_id), NULL); > + > + return p->surfaces[surface_id].context.canvas; > +} > + > +static void drawables_init(DisplayChannel *display); > +static void > +display_channel_init(DisplayChannel *self) > +{ > + static SpiceImageSurfacesOps image_surfaces_ops = { > + image_surfaces_get, > + }; > + > + self->priv = DISPLAY_CHANNEL_PRIVATE(self); > + self->priv->pub = self; > + > + stat_compress_init(&self->priv->lz_stat, "lz", CLOCK_THREAD_CPUTIME_ID); > + stat_compress_init(&self->priv->glz_stat, "glz", > CLOCK_THREAD_CPUTIME_ID); > + stat_compress_init(&self->priv->quic_stat, "quic", > CLOCK_THREAD_CPUTIME_ID); > + stat_compress_init(&self->priv->jpeg_stat, "jpeg", > CLOCK_THREAD_CPUTIME_ID); > + stat_compress_init(&self->priv->zlib_glz_stat, "zlib", > CLOCK_THREAD_CPUTIME_ID); > + stat_compress_init(&self->priv->jpeg_alpha_stat, "jpeg_alpha", > CLOCK_THREAD_CPUTIME_ID); > + stat_compress_init(&self->priv->lz4_stat, "lz4", > CLOCK_THREAD_CPUTIME_ID); > + > + ring_init(&self->priv->current_list); > + drawables_init(self); > + self->priv->image_surfaces.ops = &image_surfaces_ops; > + self->priv->streams_buf = g_new0(Stream, NUM_STREAMS); > + self->priv->items_trace = g_new0(ItemTrace, NUM_TRACE_ITEMS); > + self->priv->image_cache = g_new0(ImageCache, 1); > +} > > static void drawable_draw(DisplayChannel *display, Drawable *drawable); > > @@ -26,7 +158,7 @@ uint32_t display_channel_generate_uid(DisplayChannel > *display) > { > spice_return_val_if_fail(display != NULL, 0); > > - return ++display->bits_unique; > + return ++display->priv->bits_unique; > } > > #define stat_start(stat, var) \ > @@ -36,107 +168,111 @@ void > display_channel_compress_stats_reset(DisplayChannel *display) > { > spice_return_if_fail(display); > > - stat_reset(&display->off_stat); > - stat_reset(&display->quic_stat); > - stat_reset(&display->lz_stat); > - stat_reset(&display->glz_stat); > - stat_reset(&display->jpeg_stat); > - stat_reset(&display->zlib_glz_stat); > - stat_reset(&display->jpeg_alpha_stat); > - stat_reset(&display->lz4_stat); > + stat_reset(&display->priv->off_stat); > + stat_reset(&display->priv->quic_stat); > + stat_reset(&display->priv->lz_stat); > + stat_reset(&display->priv->glz_stat); > + stat_reset(&display->priv->jpeg_stat); > + stat_reset(&display->priv->zlib_glz_stat); > + stat_reset(&display->priv->jpeg_alpha_stat); > + stat_reset(&display->priv->lz4_stat); > } > > -void display_channel_compress_stats_print(const DisplayChannel > *display_channel) > +void display_channel_compress_stats_print(DisplayChannel *display_channel) > { > spice_return_if_fail(display_channel); > > #ifdef COMPRESS_STAT > + DisplayChannelPrivate *priv = display_channel->priv; > uint64_t glz_enc_size; > + uint32_t id; > + > + glz_enc_size = priv->enable_zlib_glz_wrap ? > + priv->zlib_glz_stat.comp_size : > + priv->glz_stat.comp_size; > > - glz_enc_size = display_channel->enable_zlib_glz_wrap ? > - display_channel->zlib_glz_stat.comp_size : > - display_channel->glz_stat.comp_size; > + g_object_get(display_channel, "id", &id, NULL); > > - spice_info("==> Compression stats for display %u", > display_channel->common.base.id); > + spice_info("==> Compression stats for display %u", id); > spice_info("Method \t count > \torig_size(MB)\tenc_size(MB)\tenc_time(s)"); > spice_info("OFF \t%8d\t%13.2f\t%12.2f\t%12.2f", > - display_channel->off_stat.count, > - stat_byte_to_mega(display_channel->off_stat.orig_size), > - stat_byte_to_mega(display_channel->off_stat.comp_size), > - stat_cpu_time_to_sec(display_channel->off_stat.total) > + priv->off_stat.count, > + stat_byte_to_mega(priv->off_stat.orig_size), > + stat_byte_to_mega(priv->off_stat.comp_size), > + stat_cpu_time_to_sec(priv->off_stat.total) > ); > spice_info("QUIC \t%8d\t%13.2f\t%12.2f\t%12.2f", > - display_channel->quic_stat.count, > - stat_byte_to_mega(display_channel->quic_stat.orig_size), > - stat_byte_to_mega(display_channel->quic_stat.comp_size), > - stat_cpu_time_to_sec(display_channel->quic_stat.total) > + priv->quic_stat.count, > + stat_byte_to_mega(priv->quic_stat.orig_size), > + stat_byte_to_mega(priv->quic_stat.comp_size), > + stat_cpu_time_to_sec(priv->quic_stat.total) > ); > spice_info("GLZ \t%8d\t%13.2f\t%12.2f\t%12.2f", > - display_channel->glz_stat.count, > - stat_byte_to_mega(display_channel->glz_stat.orig_size), > - stat_byte_to_mega(display_channel->glz_stat.comp_size), > - stat_cpu_time_to_sec(display_channel->glz_stat.total) > + priv->glz_stat.count, > + stat_byte_to_mega(priv->glz_stat.orig_size), > + stat_byte_to_mega(priv->glz_stat.comp_size), > + stat_cpu_time_to_sec(priv->glz_stat.total) > ); > spice_info("ZLIB GLZ \t%8d\t%13.2f\t%12.2f\t%12.2f", > - display_channel->zlib_glz_stat.count, > - stat_byte_to_mega(display_channel->zlib_glz_stat.orig_size), > - stat_byte_to_mega(display_channel->zlib_glz_stat.comp_size), > - stat_cpu_time_to_sec(display_channel->zlib_glz_stat.total) > + priv->zlib_glz_stat.count, > + stat_byte_to_mega(priv->zlib_glz_stat.orig_size), > + stat_byte_to_mega(priv->zlib_glz_stat.comp_size), > + stat_cpu_time_to_sec(priv->zlib_glz_stat.total) > ); > spice_info("LZ \t%8d\t%13.2f\t%12.2f\t%12.2f", > - display_channel->lz_stat.count, > - stat_byte_to_mega(display_channel->lz_stat.orig_size), > - stat_byte_to_mega(display_channel->lz_stat.comp_size), > - stat_cpu_time_to_sec(display_channel->lz_stat.total) > + priv->lz_stat.count, > + stat_byte_to_mega(priv->lz_stat.orig_size), > + stat_byte_to_mega(priv->lz_stat.comp_size), > + stat_cpu_time_to_sec(priv->lz_stat.total) > ); > spice_info("JPEG \t%8d\t%13.2f\t%12.2f\t%12.2f", > - display_channel->jpeg_stat.count, > - stat_byte_to_mega(display_channel->jpeg_stat.orig_size), > - stat_byte_to_mega(display_channel->jpeg_stat.comp_size), > - stat_cpu_time_to_sec(display_channel->jpeg_stat.total) > + priv->jpeg_stat.count, > + stat_byte_to_mega(priv->jpeg_stat.orig_size), > + stat_byte_to_mega(priv->jpeg_stat.comp_size), > + stat_cpu_time_to_sec(priv->jpeg_stat.total) > ); > spice_info("JPEG-RGBA\t%8d\t%13.2f\t%12.2f\t%12.2f", > - display_channel->jpeg_alpha_stat.count, > - > stat_byte_to_mega(display_channel->jpeg_alpha_stat.orig_size), > - > stat_byte_to_mega(display_channel->jpeg_alpha_stat.comp_size), > - stat_cpu_time_to_sec(display_channel->jpeg_alpha_stat.total) > + priv->jpeg_alpha_stat.count, > + stat_byte_to_mega(priv->jpeg_alpha_stat.orig_size), > + stat_byte_to_mega(priv->jpeg_alpha_stat.comp_size), > + stat_cpu_time_to_sec(priv->jpeg_alpha_stat.total) > ); > spice_info("LZ4 \t%8d\t%13.2f\t%12.2f\t%12.2f", > - display_channel->lz4_stat.count, > - stat_byte_to_mega(display_channel->lz4_stat.orig_size), > - stat_byte_to_mega(display_channel->lz4_stat.comp_size), > - stat_cpu_time_to_sec(display_channel->lz4_stat.total) > + priv->lz4_stat.count, > + stat_byte_to_mega(priv->lz4_stat.orig_size), > + stat_byte_to_mega(priv->lz4_stat.comp_size), > + stat_cpu_time_to_sec(priv->lz4_stat.total) > ); > spice_info("-------------------------------------------------------------------"); > spice_info("Total \t%8d\t%13.2f\t%12.2f\t%12.2f", > - display_channel->lz_stat.count + > display_channel->glz_stat.count + > - > display_channel->off_stat.count > + > - > display_channel->quic_stat.count > + > - > display_channel->jpeg_stat.count > + > - > display_channel->lz4_stat.count > + > - > display_channel->jpeg_alpha_stat.count, > - stat_byte_to_mega(display_channel->lz_stat.orig_size + > - display_channel->glz_stat.orig_size + > - display_channel->off_stat.orig_size + > - display_channel->quic_stat.orig_size + > - display_channel->jpeg_stat.orig_size + > - display_channel->lz4_stat.orig_size + > - > display_channel->jpeg_alpha_stat.orig_size), > - stat_byte_to_mega(display_channel->lz_stat.comp_size + > + display_channel->priv->lz_stat.count + > display_channel->priv->glz_stat.count + > + priv->off_stat.count + > + priv->quic_stat.count + > + priv->jpeg_stat.count + > + priv->lz4_stat.count + > + priv->jpeg_alpha_stat.count, > + stat_byte_to_mega(priv->lz_stat.orig_size + > + priv->glz_stat.orig_size + > + priv->off_stat.orig_size + > + priv->quic_stat.orig_size + > + priv->jpeg_stat.orig_size + > + priv->lz4_stat.orig_size + > + priv->jpeg_alpha_stat.orig_size), > + stat_byte_to_mega(priv->lz_stat.comp_size + > glz_enc_size + > - display_channel->off_stat.comp_size + > - display_channel->quic_stat.comp_size + > - display_channel->jpeg_stat.comp_size + > - display_channel->lz4_stat.comp_size + > - > display_channel->jpeg_alpha_stat.comp_size), > - stat_cpu_time_to_sec(display_channel->lz_stat.total + > - display_channel->glz_stat.total + > - display_channel->zlib_glz_stat.total + > - display_channel->off_stat.total + > - display_channel->quic_stat.total + > - display_channel->jpeg_stat.total + > - display_channel->lz4_stat.total + > - display_channel->jpeg_alpha_stat.total) > + priv->off_stat.comp_size + > + priv->quic_stat.comp_size + > + priv->jpeg_stat.comp_size + > + priv->lz4_stat.comp_size + > + priv->jpeg_alpha_stat.comp_size), > + stat_cpu_time_to_sec(priv->lz_stat.total + > + priv->glz_stat.total + > + priv->zlib_glz_stat.total + > + priv->off_stat.total + > + priv->quic_stat.total + > + priv->jpeg_stat.total + > + priv->lz4_stat.total + > + priv->jpeg_alpha_stat.total) > ); > #endif > } > @@ -189,7 +325,7 @@ MonitorsConfig* monitors_config_new(QXLHead *heads, > ssize_t nheads, ssize_t max) > int display_channel_get_streams_timeout(DisplayChannel *display) > { > int timeout = INT_MAX; > - Ring *ring = &display->streams; > + Ring *ring = &display->priv->streams; > RingItem *item = ring; > > red_time_t now = spice_get_monotonic_time_ns(); > @@ -227,12 +363,18 @@ void display_channel_set_stream_video(DisplayChannel > *display, int stream_video) > return; > } > > - display->stream_video = stream_video; > + display->priv->stream_video = stream_video; > +} > + > +int display_channel_get_stream_video(DisplayChannel *display) > +{ > + return display->priv->stream_video; > } > > + > static void stop_streams(DisplayChannel *display) > { > - Ring *ring = &display->streams; > + Ring *ring = &display->priv->streams; > RingItem *item = ring_get_head(ring); > > while (item) { > @@ -245,14 +387,14 @@ static void stop_streams(DisplayChannel *display) > } > } > > - display->next_item_trace = 0; > - memset(display->items_trace, 0, sizeof(display->items_trace)); > + display->priv->next_item_trace = 0; > + memset(display->priv->items_trace, 0, NUM_TRACE_ITEMS * > sizeof(*display->priv->items_trace)); > } > > void display_channel_surface_unref(DisplayChannel *display, uint32_t > surface_id) > { > - RedSurface *surface = &display->surfaces[surface_id]; > - QXLInstance *qxl = display->common.qxl; > + RedSurface *surface = &display->priv->surfaces[surface_id]; > + QXLInstance *qxl = common_graphics_channel_get_qxl(&display->parent); > DisplayChannelClient *dcc; > GList *link, *next; > > @@ -283,6 +425,13 @@ void display_channel_surface_unref(DisplayChannel > *display, uint32_t surface_id) > spice_warn_if_fail(ring_is_empty(&surface->depend_on_me)); > } > > +/* TODO: perhaps rename to "ready" or "realized" ? */ > +bool display_channel_surface_has_canvas(DisplayChannel *display, > + uint32_t surface_id) > +{ > + return display->priv->surfaces[surface_id].context.canvas != NULL; > +} > + > static void streams_update_visible_region(DisplayChannel *display, Drawable > *drawable) > { > Ring *ring; > @@ -298,7 +447,7 @@ static void streams_update_visible_region(DisplayChannel > *display, Drawable *dra > return; > } > > - ring = &display->streams; > + ring = &display->priv->streams; > item = ring_get_head(ring); > > while (item) { > @@ -312,7 +461,7 @@ static void streams_update_visible_region(DisplayChannel > *display, Drawable *dra > } > > FOREACH_DCC(display, link, next, dcc) { > - agent = dcc_get_stream_agent(dcc, get_stream_id(display, > stream)); > + agent = dcc_get_stream_agent(dcc, > display_channel_get_stream_id(display, stream)); > > if (region_intersects(&agent->vis_region, > &drawable->tree_item.base.rgn)) { > region_exclude(&agent->vis_region, > &drawable->tree_item.base.rgn); > @@ -350,7 +499,7 @@ static void pipes_add_drawable_after(DisplayChannel > *display, > pipes_add_drawable(display, drawable); > return; > } > - if (num_other_linked != display->common.base.clients_num) { > + if (num_other_linked != red_channel_get_n_clients(RED_CHANNEL(display))) > { > GList *link, *next; > spice_debug("TODO: not O(n^2)"); > FOREACH_DCC(display, link, next, dcc) { > @@ -374,11 +523,11 @@ static void current_add_drawable(DisplayChannel > *display, > RedSurface *surface; > uint32_t surface_id = drawable->surface_id; > > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > ring_add_after(&drawable->tree_item.base.siblings_link, pos); > - ring_add(&display->current_list, &drawable->list_link); > + ring_add(&display->priv->current_list, &drawable->list_link); > ring_add(&surface->current_list, &drawable->surface_list_link); > - display->current_size++; > + display->priv->current_size++; > drawable->refs++; > } > > @@ -391,7 +540,7 @@ static void current_remove_drawable(DisplayChannel > *display, Drawable *item) > ring_remove(&item->list_link); > ring_remove(&item->surface_list_link); > drawable_unref(item); > - display->current_size--; > + display->priv->current_size--; > } > > static void drawable_remove_from_pipes(Drawable *drawable) > @@ -448,7 +597,7 @@ static void current_remove(DisplayChannel *display, > TreeItem *item) > > static void current_remove_all(DisplayChannel *display, int surface_id) > { > - Ring *ring = &display->surfaces[surface_id].current; > + Ring *ring = &display->priv->surfaces[surface_id].current; > RingItem *ring_item; > > while ((ring_item = ring_get_head(ring))) { > @@ -506,7 +655,7 @@ static int current_add_equal(DisplayChannel *display, > DrawItem *item, TreeItem * > > /* sending the drawable to clients that already received > * (or will receive) other_drawable */ > - link = RED_CHANNEL(display)->clients; > + link = red_channel_get_clients(RED_CHANNEL(display)); > dpi_ring_item = ring_get_head(&other_drawable->pipes); > /* dpi contains a sublist of dcc's, ordered the same */ > while (link) { > @@ -555,7 +704,7 @@ static void __exclude_region(DisplayChannel *display, > Ring *ring, TreeItem *item > Ring **top_ring, Drawable *frame_candidate) > { > QRegion and_rgn; > - stat_start(&display->__exclude_stat, start_time); > + stat_start(&display->priv->__exclude_stat, start_time); > > region_clone(&and_rgn, rgn); > region_and(&and_rgn, &item->rgn); > @@ -617,14 +766,14 @@ static void __exclude_region(DisplayChannel *display, > Ring *ring, TreeItem *item > } > } > region_destroy(&and_rgn); > - stat_add(&display->__exclude_stat, start_time); > + stat_add(&display->priv->__exclude_stat, start_time); > } > > static void exclude_region(DisplayChannel *display, Ring *ring, RingItem > *ring_item, > QRegion *rgn, TreeItem **last, Drawable > *frame_candidate) > { > Ring *top_ring; > - stat_start(&display->exclude_stat, start_time); > + stat_start(&display->priv->exclude_stat, start_time); > > if (!ring_item) { > return; > @@ -659,7 +808,7 @@ static void exclude_region(DisplayChannel *display, Ring > *ring, RingItem *ring_i > } > > if (region_is_empty(rgn)) { > - stat_add(&display->exclude_stat, start_time); > + stat_add(&display->priv->exclude_stat, start_time); > return; > } > } > @@ -667,7 +816,7 @@ static void exclude_region(DisplayChannel *display, Ring > *ring, RingItem *ring_i > while ((last && *last == (TreeItem *)ring_item) || > !(ring_item = ring_next(ring, ring_item))) { > if (ring == top_ring) { > - stat_add(&display->exclude_stat, start_time); > + stat_add(&display->priv->exclude_stat, start_time); > return; > } > ring_item = &container->base.siblings_link; > @@ -679,9 +828,9 @@ static void exclude_region(DisplayChannel *display, Ring > *ring, RingItem *ring_i > > static int current_add_with_shadow(DisplayChannel *display, Ring *ring, > Drawable *item) > { > - stat_start(&display->add_stat, start_time); > + stat_start(&display->priv->add_stat, start_time); > #ifdef RED_WORKER_STAT > - ++display->add_with_shadow_count; > + ++display->priv->add_with_shadow_count; > #endif > > RedDrawable *red_drawable = item->red_drawable; > @@ -692,7 +841,7 @@ static int current_add_with_shadow(DisplayChannel > *display, Ring *ring, Drawable > > Shadow *shadow = shadow_new(&item->tree_item, &delta); > if (!shadow) { > - stat_add(&display->add_stat, start_time); > + stat_add(&display->priv->add_stat, start_time); > return FALSE; > } > // item and his shadow must initially be placed in the same container. > @@ -716,7 +865,7 @@ static int current_add_with_shadow(DisplayChannel > *display, Ring *ring, Drawable > stream_detach_behind(display, &item->tree_item.base.rgn, item); > } > } > - stat_add(&display->add_stat, start_time); > + stat_add(&display->priv->add_stat, start_time); > return TRUE; > } > > @@ -726,7 +875,7 @@ static int current_add(DisplayChannel *display, Ring > *ring, Drawable *drawable) > RingItem *now; > QRegion exclude_rgn; > RingItem *exclude_base = NULL; > - stat_start(&display->add_stat, start_time); > + stat_start(&display->priv->add_stat, start_time); > > spice_assert(!region_is_empty(&item->base.rgn)); > region_init(&exclude_rgn); > @@ -748,7 +897,7 @@ static int current_add(DisplayChannel *display, Ring > *ring, Drawable *drawable) > if (!(test_res & REGION_TEST_RIGHT_EXCLUSIVE) && > !(test_res & > REGION_TEST_LEFT_EXCLUSIVE) > && > current_add_equal(display, > item, sibling)) { > - stat_add(&display->add_stat, start_time); > + stat_add(&display->priv->add_stat, start_time); > return FALSE; > } > > @@ -834,7 +983,7 @@ static int current_add(DisplayChannel *display, Ring > *ring, Drawable *drawable) > } > } > region_destroy(&exclude_rgn); > - stat_add(&display->add_stat, start_time); > + stat_add(&display->priv->add_stat, start_time); > return TRUE; > } > > @@ -843,7 +992,7 @@ static bool drawable_can_stream(DisplayChannel *display, > Drawable *drawable) > RedDrawable *red_drawable = drawable->red_drawable; > SpiceImage *image; > > - if (display->stream_video == SPICE_STREAM_VIDEO_OFF) { > + if (display->priv->stream_video == SPICE_STREAM_VIDEO_OFF) { > return FALSE; > } > > @@ -863,7 +1012,7 @@ static bool drawable_can_stream(DisplayChannel *display, > Drawable *drawable) > return FALSE; > } > > - if (display->stream_video == SPICE_STREAM_VIDEO_FILTER) { > + if (display->priv->stream_video == SPICE_STREAM_VIDEO_FILTER) { > SpiceRect* rect; > int size; > > @@ -880,26 +1029,26 @@ static bool drawable_can_stream(DisplayChannel > *display, Drawable *drawable) > void display_channel_print_stats(DisplayChannel *display) > { > #ifdef RED_WORKER_STAT > - stat_time_t total = display->add_stat.total; > + stat_time_t total = display->priv->add_stat.total; > spice_info("add with shadow count %u", > - display->add_with_shadow_count); > - display->add_with_shadow_count = 0; > + display->priv->add_with_shadow_count); > + display->priv->add_with_shadow_count = 0; > spice_info("add[%u] %f exclude[%u] %f __exclude[%u] %f", > - display->add_stat.count, > + display->priv->add_stat.count, > stat_cpu_time_to_sec(total), > - display->exclude_stat.count, > - stat_cpu_time_to_sec(display->exclude_stat.total), > - display->__exclude_stat.count, > - stat_cpu_time_to_sec(display->__exclude_stat.total)); > + display->priv->exclude_stat.count, > + stat_cpu_time_to_sec(display->priv->exclude_stat.total), > + display->priv->__exclude_stat.count, > + stat_cpu_time_to_sec(display->priv->__exclude_stat.total)); > spice_info("add %f%% exclude %f%% exclude2 %f%% __exclude %f%%", > - (double)(total - display->exclude_stat.total) / total * 100, > - (double)(display->exclude_stat.total) / total * 100, > - (double)(display->exclude_stat.total - > - display->__exclude_stat.total) / > display->exclude_stat.total * 100, > - (double)(display->__exclude_stat.total) / > display->exclude_stat.total * 100); > - stat_reset(&display->add_stat); > - stat_reset(&display->exclude_stat); > - stat_reset(&display->__exclude_stat); > + (double)(total - display->priv->exclude_stat.total) / total * > 100, > + (double)(display->priv->exclude_stat.total) / total * 100, > + (double)(display->priv->exclude_stat.total - > + display->priv->__exclude_stat.total) / > display->priv->exclude_stat.total * 100, > + (double)(display->priv->__exclude_stat.total) / > display->priv->exclude_stat.total * 100); > + stat_reset(&display->priv->add_stat); > + stat_reset(&display->priv->exclude_stat); > + stat_reset(&display->priv->__exclude_stat); > #endif > } > > @@ -914,7 +1063,7 @@ static void drawable_ref_surface_deps(DisplayChannel > *display, Drawable *drawabl > if (surface_id == -1) { > continue; > } > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > surface->refs++; > } > } > @@ -923,7 +1072,7 @@ static void surface_read_bits(DisplayChannel *display, > int surface_id, > const SpiceRect *area, uint8_t *dest, int > dest_stride) > { > SpiceCanvas *canvas; > - RedSurface *surface = &display->surfaces[surface_id]; > + RedSurface *surface = &display->priv->surfaces[surface_id]; > > canvas = surface->context.canvas; > canvas->ops->read_bits(canvas, dest, dest_stride, area); > @@ -941,7 +1090,7 @@ static void handle_self_bitmap(DisplayChannel *display, > Drawable *drawable) > int bpp; > int all_set; > > - surface = &display->surfaces[drawable->surface_id]; > + surface = &display->priv->surfaces[drawable->surface_id]; > > bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8; > width = red_drawable->self_bitmap_area.right - > red_drawable->self_bitmap_area.left; > @@ -993,7 +1142,7 @@ static void > surface_add_reverse_dependency(DisplayChannel *display, int surface_ > return; > } > > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > > depend_item->drawable = drawable; > ring_add(&surface->depend_on_me, &depend_item->ring_item); > @@ -1027,7 +1176,7 @@ static void draw_depend_on_me(DisplayChannel *display, > uint32_t surface_id) > RedSurface *surface; > RingItem *ring_item; > > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > > while ((ring_item = ring_get_tail(&surface->depend_on_me))) { > Drawable *drawable; > @@ -1045,10 +1194,10 @@ static int validate_drawable_bbox(DisplayChannel > *display, RedDrawable *drawable > /* surface_id must be validated before calling into > * validate_drawable_bbox > */ > - if (!validate_surface(display, drawable->surface_id)) { > + if (!display_channel_validate_surface(display, > drawable->surface_id)) { > return FALSE; > } > - context = &display->surfaces[surface_id].context; > + context = &display->priv->surfaces[surface_id].context; > > if (drawable->bbox.top < 0) > return FALSE; > @@ -1088,7 +1237,7 @@ static Drawable > *display_channel_get_drawable(DisplayChannel *display, uint8_t e > } > for (x = 0; x < 3; ++x) { > if (red_drawable->surface_deps[x] != -1 > - && !validate_surface(display, red_drawable->surface_deps[x])) { > + && !display_channel_validate_surface(display, > red_drawable->surface_deps[x])) { > return NULL; > } > } > @@ -1102,7 +1251,7 @@ static Drawable > *display_channel_get_drawable(DisplayChannel *display, uint8_t e > drawable->red_drawable = red_drawable_ref(red_drawable); > > drawable->surface_id = red_drawable->surface_id; > - display->surfaces[drawable->surface_id].refs++; > + display->priv->surfaces[drawable->surface_id].refs++; > > memcpy(drawable->surface_deps, red_drawable->surface_deps, > sizeof(drawable->surface_deps)); > /* > @@ -1152,7 +1301,7 @@ static void display_channel_add_drawable(DisplayChannel > *display, Drawable *draw > return; > } > > - Ring *ring = &display->surfaces[surface_id].current; > + Ring *ring = &display->priv->surfaces[surface_id].current; > int add_to_pipe; > if (has_shadow(red_drawable)) { > add_to_pipe = current_add_with_shadow(display, ring, drawable); > @@ -1165,7 +1314,7 @@ static void display_channel_add_drawable(DisplayChannel > *display, Drawable *draw > pipes_add_drawable(display, drawable); > > #ifdef RED_WORKER_STAT > - if ((++display->add_count % 100) == 0) > + if ((++display->priv->add_count % 100) == 0) > display_channel_print_stats(display); > #endif > } > @@ -1189,18 +1338,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 = channel->clients->data; > + rcc = clients->data; > > g_object_ref(rcc); > for (;;) { > @@ -1228,8 +1377,8 @@ void display_channel_flush_all_surfaces(DisplayChannel > *display) > { > int x; > > - for (x = 0; x < NUM_SURFACES; ++x) { > - if (display->surfaces[x].context.canvas) { > + for (x = 0; x < display->priv->n_surfaces; ++x) { > + if (display->priv->surfaces[x].context.canvas) { > display_channel_current_flush(display, x); > } > } > @@ -1261,7 +1410,7 @@ void display_channel_free_glz_drawables(DisplayChannel > *display) > > static bool free_one_drawable(DisplayChannel *display, int force_glz_free) > { > - RingItem *ring_item = ring_get_tail(&display->current_list); > + RingItem *ring_item = ring_get_tail(&display->priv->current_list); > Drawable *drawable; > Container *container; > > @@ -1287,7 +1436,7 @@ static bool free_one_drawable(DisplayChannel *display, > int force_glz_free) > > void display_channel_current_flush(DisplayChannel *display, int surface_id) > { > - while (!ring_is_empty(&display->surfaces[surface_id].current_list)) { > + while > (!ring_is_empty(&display->priv->surfaces[surface_id].current_list)) { > free_one_drawable(display, FALSE); > } > current_remove_all(display, surface_id); > @@ -1299,7 +1448,7 @@ void display_channel_free_some(DisplayChannel *display) > DisplayChannelClient *dcc; > GList *link, *next; > > - spice_debug("#draw=%d, #glz_draw=%d", display->drawable_count, > + spice_debug("#draw=%d, #glz_draw=%d", display->priv->drawable_count, > display->glz_drawable_count); > FOREACH_DCC(display, link, next, dcc) { > GlzSharedDictionary *glz_dict = dcc_get_glz_dictionary(dcc); > @@ -1312,7 +1461,7 @@ void display_channel_free_some(DisplayChannel *display) > } > } > > - while (!ring_is_empty(&display->current_list) && n++ < > RED_RELEASE_BUNCH_SIZE) { > + while (!ring_is_empty(&display->priv->current_list) && n++ < > RED_RELEASE_BUNCH_SIZE) { > free_one_drawable(display, TRUE); > } > > @@ -1329,29 +1478,30 @@ static Drawable* drawable_try_new(DisplayChannel > *display) > { > Drawable *drawable; > > - if (!display->free_drawables) > + if (!display->priv->free_drawables) > return NULL; > > - drawable = &display->free_drawables->u.drawable; > - display->free_drawables = display->free_drawables->u.next; > - display->drawable_count++; > + drawable = &display->priv->free_drawables->u.drawable; > + display->priv->free_drawables = display->priv->free_drawables->u.next; > + display->priv->drawable_count++; > > return drawable; > } > > static void drawable_free(DisplayChannel *display, Drawable *drawable) > { > - ((_Drawable *)drawable)->u.next = display->free_drawables; > - display->free_drawables = (_Drawable *)drawable; > + ((_Drawable *)drawable)->u.next = display->priv->free_drawables; > + display->priv->free_drawables = (_Drawable *)drawable; > } > > static void drawables_init(DisplayChannel *display) > { > int i; > > - display->free_drawables = NULL; > + display->priv->drawables = g_new0(_Drawable, NUM_DRAWABLES); > + display->priv->free_drawables = NULL; > for (i = 0; i < NUM_DRAWABLES; i++) { > - drawable_free(display, &display->drawables[i].u.drawable); > + drawable_free(display, &display->priv->drawables[i].u.drawable); > } > } > > @@ -1449,11 +1599,12 @@ void drawable_unref(Drawable *drawable) > SPICE_CONTAINEROF(item, RedGlzDrawable, drawable_link)->drawable = > NULL; > ring_remove(item); > } > + > if (drawable->red_drawable) { > red_drawable_unref(drawable->red_drawable); > } > drawable_free(display, drawable); > - display->drawable_count--; > + display->priv->drawable_count--; > } > > static void drawable_deps_draw(DisplayChannel *display, Drawable *drawable) > @@ -1478,11 +1629,11 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > > drawable_deps_draw(display, drawable); > > - surface = &display->surfaces[drawable->surface_id]; > + surface = &display->priv->surfaces[drawable->surface_id]; > canvas = surface->context.canvas; > spice_return_if_fail(canvas); > > - image_cache_aging(&display->image_cache); > + image_cache_aging(display->priv->image_cache); > > region_add(&surface->draw_dirty_region, &drawable->red_drawable->bbox); > > @@ -1490,8 +1641,8 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_FILL: { > SpiceFill fill = drawable->red_drawable->u.fill; > SpiceImage img1, img2; > - image_cache_localize_brush(&display->image_cache, &fill.brush, > &img1); > - image_cache_localize_mask(&display->image_cache, &fill.mask, &img2); > + image_cache_localize_brush(display->priv->image_cache, &fill.brush, > &img1); > + image_cache_localize_mask(display->priv->image_cache, &fill.mask, > &img2); > canvas->ops->draw_fill(canvas, &drawable->red_drawable->bbox, > &clip, &fill); > break; > @@ -1499,17 +1650,17 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_OPAQUE: { > SpiceOpaque opaque = drawable->red_drawable->u.opaque; > SpiceImage img1, img2, img3; > - image_cache_localize_brush(&display->image_cache, &opaque.brush, > &img1); > - image_cache_localize(&display->image_cache, &opaque.src_bitmap, > &img2, drawable); > - image_cache_localize_mask(&display->image_cache, &opaque.mask, > &img3); > + image_cache_localize_brush(display->priv->image_cache, > &opaque.brush, &img1); > + image_cache_localize(display->priv->image_cache, &opaque.src_bitmap, > &img2, drawable); > + image_cache_localize_mask(display->priv->image_cache, &opaque.mask, > &img3); > canvas->ops->draw_opaque(canvas, &drawable->red_drawable->bbox, > &clip, &opaque); > break; > } > case QXL_DRAW_COPY: { > SpiceCopy copy = drawable->red_drawable->u.copy; > SpiceImage img1, img2; > - image_cache_localize(&display->image_cache, ©.src_bitmap, &img1, > drawable); > - image_cache_localize_mask(&display->image_cache, ©.mask, &img2); > + image_cache_localize(display->priv->image_cache, ©.src_bitmap, > &img1, drawable); > + image_cache_localize_mask(display->priv->image_cache, ©.mask, > &img2); > canvas->ops->draw_copy(canvas, &drawable->red_drawable->bbox, > &clip, ©); > break; > @@ -1517,7 +1668,7 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_TRANSPARENT: { > SpiceTransparent transparent = > drawable->red_drawable->u.transparent; > SpiceImage img1; > - image_cache_localize(&display->image_cache, &transparent.src_bitmap, > &img1, drawable); > + image_cache_localize(display->priv->image_cache, > &transparent.src_bitmap, &img1, drawable); > canvas->ops->draw_transparent(canvas, > &drawable->red_drawable->bbox, &clip, > &transparent); > break; > @@ -1525,7 +1676,7 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_ALPHA_BLEND: { > SpiceAlphaBlend alpha_blend = drawable->red_drawable->u.alpha_blend; > SpiceImage img1; > - image_cache_localize(&display->image_cache, &alpha_blend.src_bitmap, > &img1, drawable); > + image_cache_localize(display->priv->image_cache, > &alpha_blend.src_bitmap, &img1, drawable); > canvas->ops->draw_alpha_blend(canvas, > &drawable->red_drawable->bbox, &clip, > &alpha_blend); > break; > @@ -1538,8 +1689,8 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_BLEND: { > SpiceBlend blend = drawable->red_drawable->u.blend; > SpiceImage img1, img2; > - image_cache_localize(&display->image_cache, &blend.src_bitmap, > &img1, drawable); > - image_cache_localize_mask(&display->image_cache, &blend.mask, > &img2); > + image_cache_localize(display->priv->image_cache, &blend.src_bitmap, > &img1, drawable); > + image_cache_localize_mask(display->priv->image_cache, &blend.mask, > &img2); > canvas->ops->draw_blend(canvas, &drawable->red_drawable->bbox, > &clip, &blend); > break; > @@ -1547,7 +1698,7 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_BLACKNESS: { > SpiceBlackness blackness = drawable->red_drawable->u.blackness; > SpiceImage img1; > - image_cache_localize_mask(&display->image_cache, &blackness.mask, > &img1); > + image_cache_localize_mask(display->priv->image_cache, > &blackness.mask, &img1); > canvas->ops->draw_blackness(canvas, > &drawable->red_drawable->bbox, &clip, > &blackness); > break; > @@ -1555,7 +1706,7 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_WHITENESS: { > SpiceWhiteness whiteness = drawable->red_drawable->u.whiteness; > SpiceImage img1; > - image_cache_localize_mask(&display->image_cache, &whiteness.mask, > &img1); > + image_cache_localize_mask(display->priv->image_cache, > &whiteness.mask, &img1); > canvas->ops->draw_whiteness(canvas, > &drawable->red_drawable->bbox, &clip, > &whiteness); > break; > @@ -1563,7 +1714,7 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_INVERS: { > SpiceInvers invers = drawable->red_drawable->u.invers; > SpiceImage img1; > - image_cache_localize_mask(&display->image_cache, &invers.mask, > &img1); > + image_cache_localize_mask(display->priv->image_cache, &invers.mask, > &img1); > canvas->ops->draw_invers(canvas, > &drawable->red_drawable->bbox, &clip, > &invers); > break; > @@ -1571,9 +1722,9 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_ROP3: { > SpiceRop3 rop3 = drawable->red_drawable->u.rop3; > SpiceImage img1, img2, img3; > - image_cache_localize_brush(&display->image_cache, &rop3.brush, > &img1); > - image_cache_localize(&display->image_cache, &rop3.src_bitmap, &img2, > drawable); > - image_cache_localize_mask(&display->image_cache, &rop3.mask, &img3); > + image_cache_localize_brush(display->priv->image_cache, &rop3.brush, > &img1); > + image_cache_localize(display->priv->image_cache, &rop3.src_bitmap, > &img2, drawable); > + image_cache_localize_mask(display->priv->image_cache, &rop3.mask, > &img3); > canvas->ops->draw_rop3(canvas, &drawable->red_drawable->bbox, > &clip, &rop3); > break; > @@ -1581,9 +1732,9 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_COMPOSITE: { > SpiceComposite composite = drawable->red_drawable->u.composite; > SpiceImage src, mask; > - image_cache_localize(&display->image_cache, &composite.src_bitmap, > &src, drawable); > + image_cache_localize(display->priv->image_cache, > &composite.src_bitmap, &src, drawable); > if (composite.mask_bitmap) > - image_cache_localize(&display->image_cache, > &composite.mask_bitmap, &mask, drawable); > + image_cache_localize(display->priv->image_cache, > &composite.mask_bitmap, &mask, drawable); > canvas->ops->draw_composite(canvas, &drawable->red_drawable->bbox, > &clip, &composite); > break; > @@ -1591,7 +1742,7 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_STROKE: { > SpiceStroke stroke = drawable->red_drawable->u.stroke; > SpiceImage img1; > - image_cache_localize_brush(&display->image_cache, &stroke.brush, > &img1); > + image_cache_localize_brush(display->priv->image_cache, > &stroke.brush, &img1); > canvas->ops->draw_stroke(canvas, > &drawable->red_drawable->bbox, &clip, > &stroke); > break; > @@ -1599,8 +1750,8 @@ static void drawable_draw(DisplayChannel *display, > Drawable *drawable) > case QXL_DRAW_TEXT: { > SpiceText text = drawable->red_drawable->u.text; > SpiceImage img1, img2; > - image_cache_localize_brush(&display->image_cache, &text.fore_brush, > &img1); > - image_cache_localize_brush(&display->image_cache, &text.back_brush, > &img2); > + image_cache_localize_brush(display->priv->image_cache, > &text.fore_brush, &img1); > + image_cache_localize_brush(display->priv->image_cache, > &text.back_brush, &img2); > canvas->ops->draw_text(canvas, &drawable->red_drawable->bbox, > &clip, &text); > break; > @@ -1692,11 +1843,11 @@ void display_channel_draw_until(DisplayChannel > *display, const SpiceRect *area, > spice_return_if_fail(last); > spice_return_if_fail(ring_item_is_linked(&last->list_link)); > > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > > if (surface_id != last->surface_id) { > // find the nearest older drawable from the appropriate surface > - ring = &display->current_list; > + ring = &display->priv->current_list; > ring_item = &last->list_link; > while ((ring_item = ring_next(ring, ring_item))) { > now = SPICE_CONTAINEROF(ring_item, Drawable, list_link); > @@ -1732,12 +1883,12 @@ void display_channel_draw(DisplayChannel *display, > const SpiceRect *area, int su > spice_debug("surface %d: area ==>", surface_id); > rect_debug(area); > > - spice_return_if_fail(surface_id >= 0 && surface_id < NUM_SURFACES); > + spice_return_if_fail(surface_id >= 0 && surface_id < > display->priv->n_surfaces); > spice_return_if_fail(area); > spice_return_if_fail(area->left >= 0 && area->top >= 0 && > area->left < area->right && area->top < > area->bottom); > > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > > last = current_find_intersects_rect(&surface->current_list, NULL, area); > if (last) > @@ -1769,12 +1920,12 @@ void display_channel_update(DisplayChannel *display, > SpiceRect rect; > RedSurface *surface; > > - spice_return_if_fail(validate_surface(display, surface_id)); > + spice_return_if_fail(display_channel_validate_surface(display, > surface_id)); > > red_get_rect_ptr(&rect, area); > display_channel_draw(display, &rect, surface_id); > > - surface = &display->surfaces[surface_id]; > + surface = &display->priv->surfaces[surface_id]; > if (*qxl_dirty_rects == NULL) { > *num_dirty_rects = > pixman_region32_n_rects(&surface->draw_dirty_region); > *qxl_dirty_rects = spice_new0(QXLRect, *num_dirty_rects); > @@ -1812,9 +1963,9 @@ void display_channel_destroy_surface(DisplayChannel > *display, uint32_t surface_i > > void display_channel_destroy_surface_wait(DisplayChannel *display, uint32_t > surface_id) > { > - if (!validate_surface(display, surface_id)) > + if (!display_channel_validate_surface(display, surface_id)) > return; > - if (!display->surfaces[surface_id].context.canvas) > + if (!display->priv->surfaces[surface_id].context.canvas) > return; > > draw_depend_on_me(display, surface_id); > @@ -1833,16 +1984,16 @@ void display_channel_destroy_surfaces(DisplayChannel > *display) > > spice_debug(NULL); > //to handle better > - for (i = 0; i < NUM_SURFACES; ++i) { > - if (display->surfaces[i].context.canvas) { > + for (i = 0; i < display->priv->n_surfaces; ++i) { > + if (display->priv->surfaces[i].context.canvas) { > display_channel_destroy_surface_wait(display, i); > - if (display->surfaces[i].context.canvas) { > + if (display->priv->surfaces[i].context.canvas) { > display_channel_surface_unref(display, i); > } > - spice_assert(!display->surfaces[i].context.canvas); > + spice_assert(!display->priv->surfaces[i].context.canvas); > } > } > - spice_warn_if_fail(ring_is_empty(&display->streams)); > + spice_warn_if_fail(ring_is_empty(&display->priv->streams)); > > if (red_channel_is_connected(RED_CHANNEL(display))) { > red_channel_pipes_add_type(RED_CHANNEL(display), > RED_PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE); > @@ -1873,8 +2024,8 @@ create_canvas_for_surface(DisplayChannel *display, > RedSurface *surface, uint32_t > case RED_RENDERER_SW: > canvas = canvas_create_for_data(surface->context.width, > surface->context.height, surface->context.format, > surface->context.line_0, > surface->context.stride, > - &display->image_cache.base, > - &display->image_surfaces, NULL, > NULL, NULL); > + &display->priv->image_cache->base, > + &display->priv->image_surfaces, > NULL, NULL, NULL); > surface->context.top_down = TRUE; > surface->context.canvas_draws_on_surface = TRUE; > return canvas; > @@ -1889,7 +2040,7 @@ void display_channel_create_surface(DisplayChannel > *display, uint32_t surface_id > uint32_t height, int32_t stride, > uint32_t format, > void *line_0, int data_is_valid, int > send_client) > { > - RedSurface *surface = &display->surfaces[surface_id]; > + RedSurface *surface = &display->priv->surfaces[surface_id]; > > spice_warn_if_fail(!surface->context.canvas); > > @@ -1914,21 +2065,21 @@ void display_channel_create_surface(DisplayChannel > *display, uint32_t surface_id > region_init(&surface->draw_dirty_region); > surface->refs = 1; > > - if (display->renderer == RED_RENDERER_INVALID) { > + if (display->priv->renderer == RED_RENDERER_INVALID) { > int i; > - QXLInstance *qxl = display->common.qxl; > + QXLInstance *qxl = > common_graphics_channel_get_qxl(&display->parent); > RedsState *reds = red_qxl_get_server(qxl->st); > GArray *renderers = reds_get_renderers(reds); > for (i = 0; i < renderers->len; i++) { > uint32_t renderer = g_array_index(renderers, uint32_t, i); > surface->context.canvas = create_canvas_for_surface(display, > surface, renderer); > if (surface->context.canvas) { > - display->renderer = renderer; > + display->priv->renderer = renderer; > break; > } > } > } else { > - surface->context.canvas = create_canvas_for_surface(display, > surface, display->renderer); > + surface->context.canvas = create_canvas_for_surface(display, > surface, display->priv->renderer); > } > > spice_return_if_fail(surface->context.canvas); > @@ -1952,7 +2103,7 @@ static void on_disconnect(RedChannelClient *rcc) > > // this was the last channel client > spice_debug("#draw=%d, #glz_draw=%d", > - display->drawable_count, > + display->priv->drawable_count, > display->glz_drawable_count); > } > > @@ -2007,72 +2158,27 @@ static int handle_migrate_data(RedChannelClient *rcc, > uint32_t size, void *messa > return dcc_handle_migrate_data(DISPLAY_CHANNEL_CLIENT(rcc), size, > message); > } > > -static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, > uint32_t surface_id) > -{ > - DisplayChannel *display = SPICE_CONTAINEROF(surfaces, DisplayChannel, > image_surfaces); > - > - spice_return_val_if_fail(validate_surface(display, surface_id), NULL); > - > - return display->surfaces[surface_id].context.canvas; > -} > - > -DisplayChannel* display_channel_new(SpiceServer *reds, RedWorker *worker, > +DisplayChannel* display_channel_new(SpiceServer *reds, > + QXLInstance *qxl, > + const SpiceCoreInterfaceInternal* core, > int migrate, int stream_video, > uint32_t n_surfaces) > { > DisplayChannel *display; > - ChannelCbs cbs = { > - .on_disconnect = on_disconnect, > - .send_item = send_item, > - .hold_item = hold_item, > - .release_item = release_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 > - }; > - static SpiceImageSurfacesOps image_surfaces_ops = { > - image_surfaces_get, > - }; > > + /* FIXME: migrate is not used...? */ > spice_info("create display channel"); > - display = (DisplayChannel *)red_worker_new_channel( > - worker, sizeof(*display), "display_channel", > - SPICE_CHANNEL_DISPLAY, > - SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER, > - &cbs, dcc_handle_message); > - spice_return_val_if_fail(display, NULL); > - > - clockid_t stat_clock = CLOCK_THREAD_CPUTIME_ID; > - stat_init(&display->add_stat, "add", stat_clock); > - stat_init(&display->exclude_stat, "exclude", stat_clock); > - stat_init(&display->__exclude_stat, "__exclude", stat_clock); > -#ifdef RED_STATISTICS > - RedChannel *channel = RED_CHANNEL(display); > - display->cache_hits_counter = stat_add_counter(reds, channel->stat, > - "cache_hits", TRUE); > - display->add_to_cache_counter = stat_add_counter(reds, channel->stat, > - "add_to_cache", TRUE); > - display->non_cache_counter = stat_add_counter(reds, channel->stat, > - "non_cache", TRUE); > -#endif > - stat_compress_init(&display->lz_stat, "lz", stat_clock); > - stat_compress_init(&display->glz_stat, "glz", stat_clock); > - stat_compress_init(&display->quic_stat, "quic", stat_clock); > - stat_compress_init(&display->jpeg_stat, "jpeg", stat_clock); > - stat_compress_init(&display->zlib_glz_stat, "zlib", stat_clock); > - stat_compress_init(&display->jpeg_alpha_stat, "jpeg_alpha", stat_clock); > - stat_compress_init(&display->lz4_stat, "lz4", stat_clock); > - > - display->n_surfaces = n_surfaces; > - display->renderer = RED_RENDERER_INVALID; > - > - ring_init(&display->current_list); > - display->image_surfaces.ops = &image_surfaces_ops; > - drawables_init(display); > - image_cache_init(&display->image_cache); > - display->stream_video = stream_video; > - display_channel_init_streams(display); > - > + 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, > + NULL); > + if (display) { > + display_channel_set_stream_video(display, stream_video); > + } > return display; > } > > @@ -2084,11 +2190,11 @@ void > display_channel_process_surface_cmd(DisplayChannel *display, RedSurfaceCmd > uint8_t *data; > > surface_id = surface->surface_id; > - if SPICE_UNLIKELY(surface_id >= display->n_surfaces) { > + if SPICE_UNLIKELY(surface_id >= display->priv->n_surfaces) { > return; > } > > - red_surface = &display->surfaces[surface_id]; > + red_surface = &display->priv->surfaces[surface_id]; > > switch (surface->type) { > case QXL_SURFACE_CMD_CREATE: { > @@ -2129,18 +2235,18 @@ void > display_channel_update_compression(DisplayChannel *display, DisplayChannelC > { > gboolean is_low_bw = > common_graphics_channel_client_is_low_bandwidth(COMMON_GRAPHICS_CHANNEL_CLIENT(dcc)); > if (dcc_get_jpeg_state(dcc) == SPICE_WAN_COMPRESSION_AUTO) { > - display->enable_jpeg = is_low_bw; > + display->priv->enable_jpeg = is_low_bw; > } else { > - display->enable_jpeg = (dcc_get_jpeg_state(dcc) == > SPICE_WAN_COMPRESSION_ALWAYS); > + display->priv->enable_jpeg = (dcc_get_jpeg_state(dcc) == > SPICE_WAN_COMPRESSION_ALWAYS); > } > > if (dcc_get_zlib_glz_state(dcc) == SPICE_WAN_COMPRESSION_AUTO) { > - display->enable_zlib_glz_wrap = is_low_bw; > + display->priv->enable_zlib_glz_wrap = is_low_bw; > } else { > - display->enable_zlib_glz_wrap = (dcc_get_zlib_glz_state(dcc) == > SPICE_WAN_COMPRESSION_ALWAYS); > + display->priv->enable_zlib_glz_wrap = (dcc_get_zlib_glz_state(dcc) > == SPICE_WAN_COMPRESSION_ALWAYS); > } > - spice_info("jpeg %s", display->enable_jpeg ? "enabled" : "disabled"); > - spice_info("zlib-over-glz %s", display->enable_zlib_glz_wrap ? "enabled" > : "disabled"); > + spice_info("jpeg %s", display->priv->enable_jpeg ? "enabled" : > "disabled"); > + spice_info("zlib-over-glz %s", display->priv->enable_zlib_glz_wrap ? > "enabled" : "disabled"); > } > > void display_channel_gl_scanout(DisplayChannel *display) > @@ -2150,9 +2256,9 @@ void display_channel_gl_scanout(DisplayChannel > *display) > > static void set_gl_draw_async_count(DisplayChannel *display, int num) > { > - QXLInstance *qxl = display->common.qxl; > + QXLInstance *qxl = common_graphics_channel_get_qxl(&display->parent); > > - display->gl_draw_async_count = num; > + display->priv->gl_draw_async_count = num; > > if (num == 0) { > red_qxl_gl_draw_async_complete(qxl); > @@ -2163,7 +2269,7 @@ void display_channel_gl_draw(DisplayChannel *display, > SpiceMsgDisplayGlDraw *dra > { > int num; > > - spice_return_if_fail(display->gl_draw_async_count == 0); > + spice_return_if_fail(display->priv->gl_draw_async_count == 0); > > num = red_channel_pipes_new_add_push(RED_CHANNEL(display), > dcc_gl_draw_item_new, draw); > set_gl_draw_async_count(display, num); > @@ -2171,5 +2277,93 @@ void display_channel_gl_draw(DisplayChannel *display, > SpiceMsgDisplayGlDraw *dra > > void display_channel_gl_draw_done(DisplayChannel *display) > { > - set_gl_draw_async_count(display, display->gl_draw_async_count - 1); > + set_gl_draw_async_count(display, display->priv->gl_draw_async_count - > 1); > +} > + > +int display_channel_get_stream_id(DisplayChannel *display, Stream *stream) > +{ > + return (int)(stream - display->priv->streams_buf); > +} > + > +gboolean display_channel_validate_surface(DisplayChannel *display, uint32_t > surface_id) > +{ > + if SPICE_UNLIKELY(surface_id >= display->priv->n_surfaces) { > + spice_warning("invalid surface_id %u", surface_id); > + return 0; > + } > + if (!display->priv->surfaces[surface_id].context.canvas) { > + spice_warning("canvas address is %p for %d (and is NULL)\n", > + &(display->priv->surfaces[surface_id].context.canvas), > surface_id); > + spice_warning("failed on %d", surface_id); > + return 0; > + } > + return 1; > +} > + > +void display_channel_update_monitors_config(DisplayChannel *display, > + QXLMonitorsConfig *config, > + uint16_t count, uint16_t > max_allowed) > +{ > + if (display->priv->monitors_config) > + monitors_config_unref(display->priv->monitors_config); > + > + display->priv->monitors_config = > + monitors_config_new(config->heads, count, max_allowed); > + > +} > + > +void display_channel_set_monitors_config_to_primary(DisplayChannel *display) > +{ > + DrawContext *context = &display->priv->surfaces[0].context; > + QXLHead head = { 0, }; > + > + spice_return_if_fail(display->priv->surfaces[0].context.canvas); > + > + if (display->priv->monitors_config) > + monitors_config_unref(display->priv->monitors_config); > + > + head.width = context->width; > + head.height = context->height; > + display->priv->monitors_config = monitors_config_new(&head, 1, 1); > +} > + > +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); > + > + g_type_class_add_private(klass, sizeof(DisplayChannelPrivate)); > + > + 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 = send_item; > + channel_class->hold_item = hold_item; > + channel_class->release_item = release_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; > + > + 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_CONSTRUCT_ONLY > | > + G_PARAM_READWRITE | > + > G_PARAM_STATIC_STRINGS)); > } > diff --git a/server/display-channel.h b/server/display-channel.h > index cb0a1e3..597d615 100644 > --- a/server/display-channel.h > +++ b/server/display-channel.h > @@ -20,31 +20,63 @@ > > #include <setjmp.h> > > -#include "common/rect.h" > -#include "reds-stream.h" > #include "cache-item.h" > -#include "pixmap-cache.h" > #include "sw-canvas.h" > -#include "stat.h" > -#include "reds.h" > -#include "memslot.h" > -#include "red-parse-qxl.h" > -#include "red-record-qxl.h" > +#include "common-graphics-channel.h" > +#include "common/rect.h" > +#include "dcc-encoders.h" > +#include "dcc.h" > #include "demarshallers.h" > -#include "red-channel.h" > -#include "red-qxl.h" > #include "dispatcher.h" > #include "main-channel.h" > -#include "migration-protocol.h" > #include "main-dispatcher.h" > +#include "memslot.h" > +#include "migration-protocol.h" > +#include "mjpeg-encoder.h" > +#include "pixmap-cache.h" > +#include "red-channel.h" > +#include "red-qxl.h" > +#include "red-parse-qxl.h" > +#include "red-record-qxl.h" > +#include "reds-stream.h" > +#include "reds.h" > #include "spice-bitmap-utils.h" > -#include "image-cache.h" > -#include "utils.h" > -#include "tree.h" > +#include "stat.h" > #include "stream.h" > -#include "dcc.h" > -#include "dcc-encoders.h" > +#include "tree.h" > +#include "utils.h" > + > +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; > + > + uint32_t glz_drawable_count; > + > + DisplayChannelPrivate *priv; > +}; > + > +struct DisplayChannelClass > +{ > + CommonGraphicsChannelClass parent_class; > +}; > + > +GType display_channel_get_type(void) G_GNUC_CONST; > + > +G_END_DECLS > typedef struct DependItem { > Drawable *drawable; > RingItem ring_item; > @@ -164,68 +196,8 @@ struct _Drawable { > } u; > }; > > -struct DisplayChannel { > - CommonGraphicsChannel common; // Must be the first thing > - 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; > - > - uint32_t glz_drawable_count; > - > - int stream_video; > - 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; > - RedCompressBuf *free_compress_bufs; > - > - 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 > - stat_info_t off_stat; > - stat_info_t lz_stat; > - stat_info_t glz_stat; > - stat_info_t quic_stat; > - stat_info_t jpeg_stat; > - stat_info_t zlib_glz_stat; > - stat_info_t jpeg_alpha_stat; > - stat_info_t lz4_stat; > -}; > - > #define FOREACH_DCC(channel, _link, _next, _data) \ > - for (_link = (channel ? RED_CHANNEL(channel)->clients : NULL), \ > + for (_link = (channel ? red_channel_get_clients(RED_CHANNEL(channel)) : > NULL), \ > _next = (_link ? _link->next : NULL), \ > _data = (_link ? _link->data : NULL); \ > _link; \ > @@ -233,10 +205,7 @@ struct DisplayChannel { > _next = (_link ? _link->next : NULL), \ > _data = (_link ? _link->data : NULL)) > > -static inline int get_stream_id(DisplayChannel *display, Stream *stream) > -{ > - return (int)(stream - display->streams_buf); > -} > +int display_channel_get_stream_id(DisplayChannel *display, Stream *stream); > > typedef struct RedSurfaceDestroyItem { > SpiceMsgSurfaceDestroy surface_destroy; > @@ -251,7 +220,8 @@ typedef struct RedUpgradeItem { > > > DisplayChannel* display_channel_new > (SpiceServer *reds, > - > RedWorker > *worker, > + > QXLInstance > *qxl, > + const > SpiceCoreInterfaceInternal* core, > int > migrate, > int > stream_video, > uint32_t > n_surfaces); > @@ -275,13 +245,16 @@ void display_channel_update > (DisplayCha > void display_channel_free_some > (DisplayChannel *display); > void display_channel_set_stream_video > (DisplayChannel *display, > int > stream_video); > +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); > Drawable * display_channel_drawable_try_new > (DisplayChannel *display, > int > process_commands_generation); > void display_channel_surface_unref > (DisplayChannel *display, > uint32_t > surface_id); > +bool display_channel_surface_has_canvas > (DisplayChannel *display, > + > uint32_t > surface_id); > void display_channel_current_flush > (DisplayChannel *display, > int > surface_id); > int display_channel_wait_for_migrate_data > (DisplayChannel *display); > @@ -306,21 +279,12 @@ void display_channel_gl_scanout > (DisplayCha > void display_channel_gl_draw > (DisplayChannel *display, > SpiceMsgDisplayGlDraw > *draw); > void display_channel_gl_draw_done > (DisplayChannel *display); > +void display_channel_update_monitors_config(DisplayChannel *display, > QXLMonitorsConfig *config, > + uint16_t count, uint16_t > max_allowed); > +void display_channel_set_monitors_config_to_primary(DisplayChannel > *display); > > -static inline int validate_surface(DisplayChannel *display, uint32_t > surface_id) > -{ > - if SPICE_UNLIKELY(surface_id >= display->n_surfaces) { > - spice_warning("invalid surface_id %u", surface_id); > - return 0; > - } > - if (!display->surfaces[surface_id].context.canvas) { > - spice_warning("canvas address is %p for %d (and is NULL)\n", > - &(display->surfaces[surface_id].context.canvas), > surface_id); > - spice_warning("failed on %d", surface_id); > - return 0; > - } > - return 1; > -} > +gboolean display_channel_validate_surface(DisplayChannel *display, uint32_t > surface_id); > +void display_channel_reset_image_cache(DisplayChannel *self); > > static inline int is_equal_path(SpicePath *path1, SpicePath *path2) > { > diff --git a/server/dummy-channel-client.c b/server/dummy-channel-client.c > index a0354fd..6f0b868 100644 > --- a/server/dummy-channel-client.c > +++ b/server/dummy-channel-client.c > @@ -36,9 +36,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; > @@ -53,6 +55,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)) { > @@ -60,7 +65,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 @@ 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..6ec7842 > --- /dev/null > +++ b/server/dummy-channel.c > @@ -0,0 +1,58 @@ > +/* dummy-channel.c */ > +#ifdef HAVE_CONFIG_H > +#include <config.h> > +#endif > + > +#include "dummy-channel.h" > + > +G_DEFINE_TYPE(DummyChannel, dummy_channel, RED_TYPE_CHANNEL) > + > +#define DUMMY_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), > TYPE_DUMMY_CHANNEL, DummyChannelPrivate)) > + > +struct DummyChannelPrivate > +{ > + gpointer padding; > +}; > + > +static void > +dummy_channel_class_init(DummyChannelClass *klass) > +{ > + g_type_class_add_private(klass, sizeof(DummyChannelPrivate)); > +} > + > +static void > +dummy_channel_init(DummyChannel *self) > +{ > + self->priv = DUMMY_CHANNEL_PRIVATE(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..dd2f005 > --- /dev/null > +++ b/server/dummy-channel.h > @@ -0,0 +1,61 @@ > +/* > + 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; > +typedef struct DummyChannelPrivate DummyChannelPrivate; > + > +struct DummyChannel > +{ > + RedChannel parent; > + > + DummyChannelPrivate *priv; > +}; > + > +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 c0fdc98..32e2cfe 100644 > --- a/server/inputs-channel.c > +++ b/server/inputs-channel.c > @@ -57,6 +57,83 @@ > #define RECEIVE_BUF_SIZE \ > (4096 + (REDS_AGENT_WINDOW_SIZE + REDS_NUM_INTERNAL_AGENT_MESSAGES) * > SPICE_AGENT_MAX_DATA_SIZE) > > +G_DEFINE_TYPE(InputsChannel, inputs_channel, RED_TYPE_CHANNEL) > + > +#define CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), > TYPE_INPUTS_CHANNEL, InputsChannelPrivate)) > + > +struct InputsChannelPrivate > +{ > + uint8_t recv_buf[RECEIVE_BUF_SIZE]; > + VDAgentMouseState mouse_state; > + int src_during_migrate; > + > + SpiceKbdInstance *keyboard; > + SpiceMouseInstance *mouse; > + SpiceTabletInstance *tablet; > +}; > + > + > +static void > +inputs_channel_get_property(GObject *object, > + guint property_id, > + GValue *value, > + GParamSpec *pspec) > +{ > + switch (property_id) > + { > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); > + } > +} > + > +static void > +inputs_channel_set_property(GObject *object, > + guint property_id, > + const GValue *value, > + GParamSpec *pspec) > +{ > + switch (property_id) > + { > + default: > + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); > + } > +} > + > +static void inputs_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 inputs_migrate(RedChannelClient *rcc); > +static SpiceTimer *key_modifiers_timer; > +static void key_modifiers_sender(void *opaque); > + > +static void > +inputs_channel_constructed(GObject *object) > +{ > + ClientCbs client_cbs = { NULL, }; > + 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(RED_CHANNEL(self), &client_cbs, NULL); > + > + red_channel_set_cap(RED_CHANNEL(self), SPICE_INPUTS_CAP_KEY_SCANCODE); > + reds_register_channel(reds, RED_CHANNEL(self)); > + > + if (!(key_modifiers_timer = reds_core_timer_add(reds, > key_modifiers_sender, self))) { > + spice_error("key modifiers timer create failed"); > + } > +} > + > +static void > +inputs_channel_init(InputsChannel *self) > +{ > + self->priv = CHANNEL_PRIVATE(self); > +} > + > struct SpiceKbdState { > bool push_ext; > > @@ -101,17 +178,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; > - > - SpiceKbdInstance *keyboard; > - SpiceMouseInstance *mouse; > - SpiceTabletInstance *tablet; > -}; > - > typedef struct RedInputsPipeItem { > RedPipeItem base; > } RedInputsPipeItem; > @@ -126,8 +192,6 @@ typedef struct RedInputsInitPipeItem { > uint8_t modifiers; > } RedInputsInitPipeItem; > > -static SpiceTimer *key_modifiers_timer; > - > > #define KEY_MODIFIERS_TTL (MSEC_PER_SEC * 2) > > @@ -139,26 +203,26 @@ void > inputs_channel_set_tablet_logical_size(InputsChannel *inputs, int x_res, in > { > SpiceTabletInterface *sif; > > - sif = SPICE_CONTAINEROF(inputs->tablet->base.sif, SpiceTabletInterface, > base); > - sif->set_logical_size(inputs->tablet, x_res, y_res); > + sif = SPICE_CONTAINEROF(inputs->priv->tablet->base.sif, > SpiceTabletInterface, base); > + sif->set_logical_size(inputs->priv->tablet, x_res, y_res); > } > > VDAgentMouseState *inputs_channel_get_mouse_state(InputsChannel *inputs) > { > - return &inputs->mouse_state; > + return &inputs->priv->mouse_state; > } > > static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, > uint16_t type, > uint32_t size) > { > - InputsChannel *inputs_channel = > (InputsChannel*)red_channel_client_get_channel(rcc); > + InputsChannel *inputs = > (InputsChannel*)red_channel_client_get_channel(rcc); > > if (size > RECEIVE_BUF_SIZE) { > spice_printerr("error: too large incoming message"); > return NULL; > } > - return inputs_channel->recv_buf; > + return inputs->priv->recv_buf; > } > > static void inputs_channel_release_msg_rcv_buf(RedChannelClient *rcc, > @@ -276,10 +340,10 @@ static void inputs_channel_send_item(RedChannelClient > *rcc, RedPipeItem *base) > static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t > size, uint16_t type, > void *message) > { > - InputsChannel *inputs_channel = (InputsChannel > *)red_channel_client_get_channel(rcc); > + InputsChannel *inputs = > 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)); > > switch (type) { > case SPICE_MSGC_INPUTS_KEY_DOWN: { > @@ -297,19 +361,19 @@ static int > inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui > if (code == 0) { > break; > } > - kbd_push_scan(inputs_channel_get_keyboard(inputs_channel), > code); > + kbd_push_scan(inputs_channel_get_keyboard(inputs), code); > } > break; > } > case SPICE_MSGC_INPUTS_KEY_SCANCODE: { > uint8_t *code = message; > for (i = 0; i < size; i++) { > - kbd_push_scan(inputs_channel_get_keyboard(inputs_channel), > code[i]); > + kbd_push_scan(inputs_channel_get_keyboard(inputs), code[i]); > } > break; > } > case SPICE_MSGC_INPUTS_MOUSE_MOTION: { > - SpiceMouseInstance *mouse = > inputs_channel_get_mouse(inputs_channel); > + SpiceMouseInstance *mouse = inputs_channel_get_mouse(inputs); > SpiceMsgcMouseMotion *mouse_motion = message; > > inputs_channel_client_on_mouse_motion(icc); > @@ -324,7 +388,7 @@ static int inputs_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, ui > } > case SPICE_MSGC_INPUTS_MOUSE_POSITION: { > SpiceMsgcMousePosition *pos = message; > - SpiceTabletInstance *tablet = > inputs_channel_get_tablet(inputs_channel); > + SpiceTabletInstance *tablet = inputs_channel_get_tablet(inputs); > > inputs_channel_client_on_mouse_motion(icc); > if (reds_get_mouse_mode(reds) != SPICE_MOUSE_MODE_CLIENT) { > @@ -337,7 +401,7 @@ static int inputs_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, ui > sif->position(tablet, pos->x, pos->y, > RED_MOUSE_STATE_TO_LOCAL(pos->buttons_state)); > break; > } > - VDAgentMouseState *mouse_state = &inputs_channel->mouse_state; > + VDAgentMouseState *mouse_state = &inputs->priv->mouse_state; > mouse_state->x = pos->x; > mouse_state->y = pos->y; > mouse_state->buttons = > RED_MOUSE_BUTTON_STATE_TO_AGENT(pos->buttons_state); > @@ -355,20 +419,20 @@ static int > inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui > } > if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) { > if (reds_config_get_agent_mouse(reds) && reds_has_vdagent(reds)) > { > - inputs_channel->mouse_state.buttons = > + inputs->priv->mouse_state.buttons = > RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_press->buttons_state) > | > (dz == -1 ? VD_AGENT_UBUTTON_MASK : 0) | > (dz == 1 ? VD_AGENT_DBUTTON_MASK : 0); > - reds_handle_agent_mouse_event(reds, > &inputs_channel->mouse_state); > - } else if (inputs_channel_get_tablet(inputs_channel)) { > + reds_handle_agent_mouse_event(reds, > &inputs->priv->mouse_state); > + } else if (inputs_channel_get_tablet(inputs)) { > 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)->base.sif, > SpiceTabletInterface, base); > + sif->wheel(inputs_channel_get_tablet(inputs), dz, > RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state)); > } > - } else if (inputs_channel_get_mouse(inputs_channel)) { > + } else if (inputs_channel_get_mouse(inputs)) { > SpiceMouseInterface *sif; > - sif = > SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif, > SpiceMouseInterface, base); > - sif->motion(inputs_channel_get_mouse(inputs_channel), 0, 0, dz, > + sif = > SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs)->base.sif, > SpiceMouseInterface, base); > + sif->motion(inputs_channel_get_mouse(inputs), 0, 0, dz, > RED_MOUSE_STATE_TO_LOCAL(mouse_press->buttons_state)); > } > break; > @@ -377,18 +441,18 @@ static int > inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui > SpiceMsgcMouseRelease *mouse_release = message; > if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) { > if (reds_config_get_agent_mouse(reds) && reds_has_vdagent(reds)) > { > - inputs_channel->mouse_state.buttons = > + inputs->priv->mouse_state.buttons = > RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_release->buttons_state); > - reds_handle_agent_mouse_event(reds, > &inputs_channel->mouse_state); > - } else if (inputs_channel_get_tablet(inputs_channel)) { > + reds_handle_agent_mouse_event(reds, > &inputs->priv->mouse_state); > + } else if (inputs_channel_get_tablet(inputs)) { > 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)->base.sif, > SpiceTabletInterface, base); > + sif->buttons(inputs_channel_get_tablet(inputs), > RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state)); > } > - } else if (inputs_channel_get_mouse(inputs_channel)) { > + } else if (inputs_channel_get_mouse(inputs)) { > SpiceMouseInterface *sif; > - sif = > SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs_channel)->base.sif, > SpiceMouseInterface, base); > - sif->buttons(inputs_channel_get_mouse(inputs_channel), > + sif = > SPICE_CONTAINEROF(inputs_channel_get_mouse(inputs)->base.sif, > SpiceMouseInterface, base); > + sif->buttons(inputs_channel_get_mouse(inputs), > RED_MOUSE_STATE_TO_LOCAL(mouse_release->buttons_state)); > } > break; > @@ -396,7 +460,7 @@ static int inputs_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, ui > case SPICE_MSGC_INPUTS_KEY_MODIFIERS: { > SpiceMsgcKeyModifiers *modifiers = message; > uint8_t leds; > - SpiceKbdInstance *keyboard = > inputs_channel_get_keyboard(inputs_channel); > + SpiceKbdInstance *keyboard = inputs_channel_get_keyboard(inputs); > > if (!keyboard) { > break; > @@ -520,17 +584,17 @@ static void inputs_connect(RedChannel *channel, > RedClient *client, > static void inputs_migrate(RedChannelClient *rcc) > { > InputsChannel *inputs = > (InputsChannel*)red_channel_client_get_channel(rcc); > - inputs->src_during_migrate = TRUE; > + inputs->priv->src_during_migrate = TRUE; > red_channel_client_default_migrate(rcc); > } > > static void inputs_channel_push_keyboard_modifiers(InputsChannel *inputs, > uint8_t modifiers) > { > - if (!inputs || !red_channel_is_connected(&inputs->base) || > - inputs->src_during_migrate) { > + if (!inputs || !red_channel_is_connected(RED_CHANNEL(inputs)) || > + inputs->priv->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); > } > > @@ -574,117 +638,113 @@ static int > inputs_channel_handle_migrate_data(RedChannelClient *rcc, > return TRUE; > } > > -InputsChannel* inputs_channel_new(RedsState *reds) > +static void > +inputs_channel_class_init(InputsChannelClass *klass) > { > - ChannelCbs channel_cbs = { NULL, }; > - 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.hold_item = inputs_channel_hold_pipe_item; > - channel_cbs.release_item = inputs_channel_release_pipe_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 = (InputsChannel *)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"); > - } > + GObjectClass *object_class = G_OBJECT_CLASS(klass); > + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass); > > - client_cbs.connect = inputs_connect; > - client_cbs.migrate = inputs_migrate; > - red_channel_register_client_cbs(&inputs->base, &client_cbs, NULL); > + g_type_class_add_private(klass, sizeof(InputsChannelPrivate)); > > - red_channel_set_cap(&inputs->base, SPICE_INPUTS_CAP_KEY_SCANCODE); > - reds_register_channel(reds, &inputs->base); > + object_class->get_property = inputs_channel_get_property; > + object_class->set_property = inputs_channel_set_property; > + 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->hold_item = inputs_channel_hold_pipe_item; > + channel_class->release_item = inputs_channel_release_pipe_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; > +} > + > +InputsChannel* inputs_channel_new(RedsState *reds) > +{ > + 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); > > - if (!(key_modifiers_timer = reds_core_timer_add(reds, > key_modifiers_sender, inputs))) { > - spice_error("key modifiers timer create failed"); > - } > - return inputs; > } > > SpiceKbdInstance* inputs_channel_get_keyboard(InputsChannel *inputs) > { > - return inputs->keyboard; > + return inputs->priv->keyboard; > } > > int inputs_channel_set_keyboard(InputsChannel *inputs, SpiceKbdInstance > *keyboard) > { > - if (inputs->keyboard) { > + if (inputs->priv->keyboard) { > spice_printerr("already have keyboard"); > return -1; > } > - inputs->keyboard = keyboard; > - inputs->keyboard->st = > spice_kbd_state_new(red_channel_get_server(&inputs->base)); > + inputs->priv->keyboard = keyboard; > + inputs->priv->keyboard->st = > spice_kbd_state_new(red_channel_get_server(RED_CHANNEL(inputs))); > return 0; > } > > SpiceMouseInstance* inputs_channel_get_mouse(InputsChannel *inputs) > { > - return inputs->mouse; > + return inputs->priv->mouse; > } > > int inputs_channel_set_mouse(InputsChannel *inputs, SpiceMouseInstance > *mouse) > { > - if (inputs->mouse) { > + if (inputs->priv->mouse) { > spice_printerr("already have mouse"); > return -1; > } > - inputs->mouse = mouse; > - inputs->mouse->st = spice_mouse_state_new(); > + inputs->priv->mouse = mouse; > + inputs->priv->mouse->st = spice_mouse_state_new(); > return 0; > } > > SpiceTabletInstance* inputs_channel_get_tablet(InputsChannel *inputs) > { > - return inputs->tablet; > + return inputs->priv->tablet; > } > > int inputs_channel_set_tablet(InputsChannel *inputs, SpiceTabletInstance > *tablet, RedsState *reds) > { > - if (inputs->tablet) { > + if (inputs->priv->tablet) { > spice_printerr("already have tablet"); > return -1; > } > - inputs->tablet = tablet; > - inputs->tablet->st = spice_tablet_state_new(); > - inputs->tablet->st->reds = reds; > + inputs->priv->tablet = tablet; > + inputs->priv->tablet->st = spice_tablet_state_new(); > + inputs->priv->tablet->st->reds = reds; > return 0; > } > > int inputs_channel_has_tablet(InputsChannel *inputs) > { > - return inputs != NULL && inputs->tablet != NULL; > + return inputs != NULL && inputs->priv->tablet != NULL; > } > > void inputs_channel_detach_tablet(InputsChannel *inputs, SpiceTabletInstance > *tablet) > { > spice_printerr(""); > - inputs->tablet = NULL; > + inputs->priv->tablet = NULL; > } > > gboolean inputs_channel_is_src_during_migrate(InputsChannel *inputs) > { > - return inputs->src_during_migrate; > + return inputs->priv->src_during_migrate; > } > > void inputs_channel_set_src_during_migrate(InputsChannel *inputs, > gboolean value) > { > - inputs->src_during_migrate = value; > + inputs->priv->src_during_migrate = value; > } > diff --git a/server/inputs-channel.h b/server/inputs-channel.h > index 5317578..1dbb3a2 100644 > --- a/server/inputs-channel.h > +++ b/server/inputs-channel.h > @@ -21,14 +21,42 @@ > // Inputs channel, dealing with keyboard, mouse, tablet. > // This include should only be used by reds.c and inputs-channel.c > > +#include <glib-object.h> > #include <stdint.h> > #include <spice/vd_agent.h> > > #include "red-channel.h" > > +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; > +typedef struct InputsChannelPrivate InputsChannelPrivate; > + > +struct InputsChannel > +{ > + RedChannel parent; > + > + InputsChannelPrivate *priv; > +}; > + > +struct InputsChannelClass > +{ > + RedChannelClass parent_class; > +}; > + > +GType inputs_channel_get_type(void) G_GNUC_CONST; > > InputsChannel* inputs_channel_new(RedsState *reds); > + > 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); > @@ -53,4 +81,6 @@ enum { > RED_PIPE_ITEM_MIGRATE_DATA, > }; > > +G_END_DECLS > + > #endif > diff --git a/server/main-channel-client.c b/server/main-channel-client.c > index 82cb5c3..f18be1c 100644 > --- a/server/main-channel-client.c > +++ b/server/main-channel-client.c > @@ -101,16 +101,6 @@ static void main_channel_client_set_property(GObject > *object, > } > } > > -static void main_channel_client_dispose(GObject *object) > -{ > - G_OBJECT_CLASS(main_channel_client_parent_class)->dispose(object); > -} > - > -static void main_channel_client_finalize(GObject *object) > -{ > - G_OBJECT_CLASS(main_channel_client_parent_class)->finalize(object); > -} > - > static void ping_timer_cb(void *opaque); > static void main_channel_client_constructed(GObject *object) > { > @@ -135,8 +125,6 @@ static void > main_channel_client_class_init(MainChannelClientClass *klass) > > object_class->get_property = main_channel_client_get_property; > object_class->set_property = main_channel_client_set_property; > - object_class->dispose = main_channel_client_dispose; > - object_class->finalize = main_channel_client_finalize; > object_class->constructed = main_channel_client_constructed; > > g_object_class_install_property(object_class, > @@ -341,15 +329,11 @@ 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) { > - 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; > - spice_assert(main_channel->num_clients_mig_wait); > - spice_assert(!seamless || main_channel->num_clients_mig_wait == 1); > - if (!--main_channel->num_clients_mig_wait) { > - reds_on_main_migrate_connected(channel->reds, seamless && > success); > - } > + main_channel_on_migrate_connected(main_channel, seamless && > success); > } else { > if (success) { > spice_printerr("client %p MIGRATE_CANCEL", client); > @@ -362,7 +346,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); > @@ -429,7 +413,10 @@ void main_channel_client_handle_pong(MainChannelClient > *mcc, SpiceMsgPing *ping, > red_channel_client_handle_message(rcc, size, SPICE_MSGC_PONG, ping); > } > #ifdef RED_STATISTICS > - stat_update_value(red_channel_client_get_channel(rcc)->reds, roundtrip); > + { > + RedChannel *channel = red_channel_client_get_channel(rcc); > + stat_update_value(red_channel_get_server(channel), roundtrip); > + } > #endif > } > > @@ -470,7 +457,7 @@ void > main_channel_client_migrate_dst_complete(MainChannelClient *mcc) > RedChannel *channel = > red_channel_client_get_channel(RED_CHANNEL_CLIENT(mcc)); > if (mcc->priv->mig_wait_prev_complete) { > if (mcc->priv->mig_wait_prev_try_seamless) { > - spice_assert(channel->clients_num == 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 { > @@ -528,9 +515,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; > } > @@ -543,11 +532,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 */ > > @@ -611,15 +602,14 @@ 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); > } > > gboolean main_channel_client_connect_semi_seamless(MainChannelClient *mcc) > { > RedChannelClient *rcc = RED_CHANNEL_CLIENT(mcc); > - MainChannel* main_channel = > SPICE_CONTAINEROF(red_channel_client_get_channel(rcc), > - MainChannel, base); > if (red_channel_client_test_remote_cap(rcc, > SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE)) > { > RedClient *client = red_channel_client_get_client(rcc); > @@ -633,7 +623,6 @@ gboolean > main_channel_client_connect_semi_seamless(MainChannelClient *mcc) > mcc->priv->mig_wait_connect = TRUE; > } > mcc->priv->mig_connect_ok = FALSE; > - main_channel->num_clients_mig_wait++; > return TRUE; > } > return FALSE; > diff --git a/server/main-channel-client.h b/server/main-channel-client.h > index 5d284ad..50713ea 100644 > --- a/server/main-channel-client.h > +++ b/server/main-channel-client.h > @@ -23,8 +23,6 @@ > > G_BEGIN_DECLS > > -typedef struct MainChannel MainChannel; > - > #define TYPE_MAIN_CHANNEL_CLIENT main_channel_client_get_type() > > #define MAIN_CHANNEL_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), > TYPE_MAIN_CHANNEL_CLIENT, MainChannelClient)) > @@ -49,6 +47,8 @@ struct MainChannelClientClass > RedChannelClientClass parent_class; > }; > > +typedef struct MainChannel MainChannel; > + > GType main_channel_client_get_type(void) G_GNUC_CONST; > > MainChannelClient *main_channel_client_create(MainChannel *main_chan, > RedClient *client, > diff --git a/server/main-channel.c b/server/main-channel.c > index e3d6c57..554c20d 100644 > --- a/server/main-channel.c > +++ b/server/main-channel.c > @@ -50,15 +50,51 @@ > #include "utils.h" > > #define ZERO_BUF_SIZE 4096 > +// 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) > > static const uint8_t zero_page[ZERO_BUF_SIZE] = {0}; > > + > +G_DEFINE_TYPE(MainChannel, main_channel, RED_TYPE_CHANNEL) > + > +#define MAIN_CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), > TYPE_MAIN_CHANNEL, MainChannelPrivate)) > + > +struct MainChannelPrivate > +{ > + 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; > +}; > + > +static void > +main_channel_constructed(GObject *object) > +{ > + MainChannel *self = MAIN_CHANNEL(object); > + ClientCbs client_cbs = { NULL, }; > + > + G_OBJECT_CLASS(main_channel_parent_class)->constructed(object); > + > + 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(RED_CHANNEL(self), &client_cbs, NULL); > +} > + > +static void > +main_channel_init(MainChannel *self) > +{ > + self->priv = MAIN_CHANNEL_PRIVATE(self); > +} > + > static void main_channel_release_pipe_item(RedChannelClient *rcc, > RedPipeItem *base, int > item_pushed); > > 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)); > } > > /* > @@ -78,7 +114,7 @@ RedClient *main_channel_get_client_by_link_id(MainChannel > *main_chan, uint32_t c > MainChannelClient *mcc; > RedChannelClient *rcc; > > - for (link = main_chan->base.clients; link != NULL; link = link->next) { > + for (link = red_channel_get_clients(RED_CHANNEL(main_chan)); link != > NULL; link = link->next) { > rcc = link->data; > mcc = MAIN_CHANNEL_CLIENT(rcc); > if (main_channel_client_get_connection_id(mcc) == connection_id) { > @@ -134,7 +170,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); > } > @@ -167,7 +203,7 @@ 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); > } > > @@ -188,10 +224,10 @@ static void > main_channel_marshall_mouse_mode(RedChannelClient *rcc, > > 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_TOKENS)) { > + red_channel_pipes_add_type(RED_CHANNEL(main_chan), > RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_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); > } > } > > @@ -208,7 +244,7 @@ static void > main_channel_marshall_agent_connected(SpiceMarshaller *m, > > 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_marshall_agent_disconnected(RedChannelClient *rcc, > @@ -242,7 +278,7 @@ static void > main_channel_marshall_agent_data(RedChannelClient *rcc, > > 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 void main_channel_marshall_migrate_data_item(RedChannelClient *rcc, > @@ -251,7 +287,7 @@ 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. > + reds_marshall_migrate_data(red_channel_get_server(channel), m); // TODO: > from reds split. ugly separation. > } > > static int main_channel_handle_migrate_data(RedChannelClient *rcc, > @@ -262,7 +298,7 @@ static int > main_channel_handle_migrate_data(RedChannelClient *rcc, > SpiceMigrateDataHeader *header = (SpiceMigrateDataHeader *)message; > > /* not supported with multi-clients */ > - spice_assert(channel->clients_num == 1); > + spice_assert(red_channel_get_n_clients(channel) == 1); > > if (size < sizeof(SpiceMigrateDataHeader) + > sizeof(SpiceMigrateDataMain)) { > spice_printerr("bad message size %u", size); > @@ -274,7 +310,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); > } > > static void main_channel_marshall_init(RedChannelClient *rcc, > @@ -292,7 +330,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; > @@ -317,7 +355,7 @@ static void main_channel_marshall_notify(RedChannelClient > *rcc, > static void main_channel_fill_migrate_dst_info(MainChannel *main_channel, > SpiceMigrationDstInfo > *dst_info) > { > - RedsMigSpice *mig_dst = &main_channel->mig_target; > + RedsMigSpice *mig_dst = &main_channel->priv->mig_target; > dst_info->port = mig_dst->port; > dst_info->sport = mig_dst->sport; > dst_info->host_size = strlen(mig_dst->host) + 1; > @@ -336,11 +374,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); > } > > @@ -350,11 +386,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); > } > @@ -365,29 +399,29 @@ 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); > } > > static void main_channel_fill_mig_target(MainChannel *main_channel, > RedsMigSpice *mig_target) > { > spice_assert(mig_target); > - free(main_channel->mig_target.host); > - main_channel->mig_target.host = spice_strdup(mig_target->host); > - free(main_channel->mig_target.cert_subject); > + free(main_channel->priv->mig_target.host); > + main_channel->priv->mig_target.host = spice_strdup(mig_target->host); > + free(main_channel->priv->mig_target.cert_subject); > if (mig_target->cert_subject) { > - main_channel->mig_target.cert_subject = > spice_strdup(mig_target->cert_subject); > + main_channel->priv->mig_target.cert_subject = > spice_strdup(mig_target->cert_subject); > } else { > - main_channel->mig_target.cert_subject = NULL; > + main_channel->priv->mig_target.cert_subject = NULL; > } > - main_channel->mig_target.port = mig_target->port; > - main_channel->mig_target.sport = mig_target->sport; > + main_channel->priv->mig_target.port = mig_target->port; > + main_channel->priv->mig_target.sport = mig_target->sport; > } > > 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 void main_channel_marshall_migrate_switch(SpiceMarshaller *m, > RedChannelClient *rcc, > @@ -395,18 +429,18 @@ static void > main_channel_marshall_migrate_switch(SpiceMarshaller *m, RedChannelC > { > RedChannel *channel = red_channel_client_get_channel(rcc); > SpiceMsgMainMigrationSwitchHost migrate; > - MainChannel *main_ch; > + MainChannel *main_chan; > > spice_printerr(""); > red_channel_client_init_send_data(rcc, > SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST, item); > - main_ch = SPICE_CONTAINEROF(channel, MainChannel, base); > - migrate.port = main_ch->mig_target.port; > - migrate.sport = main_ch->mig_target.sport; > - migrate.host_size = strlen(main_ch->mig_target.host) + 1; > - migrate.host_data = (uint8_t *)main_ch->mig_target.host; > - if (main_ch->mig_target.cert_subject) { > - migrate.cert_subject_size = strlen(main_ch->mig_target.cert_subject) > + 1; > - migrate.cert_subject_data = (uint8_t > *)main_ch->mig_target.cert_subject; > + main_chan = MAIN_CHANNEL(channel); > + migrate.port = main_chan->priv->mig_target.port; > + migrate.sport = main_chan->priv->mig_target.sport; > + migrate.host_size = strlen(main_chan->priv->mig_target.host) + 1; > + migrate.host_data = (uint8_t *)main_chan->priv->mig_target.host; > + if (main_chan->priv->mig_target.cert_subject) { > + migrate.cert_subject_size = > strlen(main_chan->priv->mig_target.cert_subject) + 1; > + migrate.cert_subject_data = (uint8_t > *)main_chan->priv->mig_target.cert_subject; > } else { > migrate.cert_subject_size = 0; > migrate.cert_subject_data = NULL; > @@ -536,8 +570,9 @@ static int main_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, uint > 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: { > @@ -548,18 +583,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: > @@ -583,7 +618,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); > @@ -605,13 +640,13 @@ 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; > + return main_chan->priv->recv_buf; > } > } > > @@ -622,7 +657,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(channel), > msg); > } > } > > @@ -639,8 +674,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; > } > > @@ -665,12 +699,12 @@ 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_chan)), 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_chan)), sa, salen) > : -1; > } > > // TODO: ? shouldn't it disonnect all clients? or shutdown all > main_channels? > @@ -678,79 +712,57 @@ 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, }; > - > - channel_cbs.config_socket = main_channel_config_socket; > - channel_cbs.on_disconnect = main_channel_client_on_disconnect; > - channel_cbs.send_item = main_channel_send_item; > - channel_cbs.hold_item = main_channel_hold_pipe_item; > - channel_cbs.release_item = main_channel_release_pipe_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; > - > // 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_parser(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); > - > - client_cbs.migrate = main_channel_client_migrate; > - red_channel_register_client_cbs(channel, &client_cbs, NULL); > - > - return (MainChannel *)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 int main_channel_connect_semi_seamless(MainChannel *main_channel) > { > GList *link; > > - for (link = main_channel->base.clients; link != NULL; link = link->next) > { > + for (link = red_channel_get_clients(RED_CHANNEL(main_channel)); link != > NULL; link = link->next) { > RedChannelClient *rcc = link->data; > MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc); > if (main_channel_client_connect_semi_seamless(mcc)) > - main_channel->num_clients_mig_wait++; > + main_channel->priv->num_clients_mig_wait++; > } > - return main_channel->num_clients_mig_wait; > + return main_channel->priv->num_clients_mig_wait; > } > > static int main_channel_connect_seamless(MainChannel *main_channel) > { > GList *link; > > - spice_assert(g_list_length(main_channel->base.clients) == 1); > + spice_assert(red_channel_get_n_clients(RED_CHANNEL(main_channel)) == 1); > > - for (link = main_channel->base.clients; link != NULL; link = link->next) > { > + for (link = red_channel_get_clients(RED_CHANNEL(main_channel)); link != > NULL; link = link->next) { > RedChannelClient *rcc = link->data; > MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc); > main_channel_client_connect_seamless(mcc); > - main_channel->num_clients_mig_wait++; > + main_channel->priv->num_clients_mig_wait++; > } > - return main_channel->num_clients_mig_wait; > + return main_channel->priv->num_clients_mig_wait; > } > > int main_channel_migrate_connect(MainChannel *main_channel, RedsMigSpice > *mig_target, > int try_seamless) > { > main_channel_fill_mig_target(main_channel, mig_target); > - main_channel->num_clients_mig_wait = 0; > + main_channel->priv->num_clients_mig_wait = 0; > > if (!main_channel_is_connected(main_channel)) { > return 0; > @@ -760,8 +772,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 = main_channel->base.clients->data; > + /* just test the first one */ > + rcc = clients->data; > > if (!red_channel_client_test_remote_cap(rcc, > SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) > { > @@ -777,27 +791,28 @@ void main_channel_migrate_cancel_wait(MainChannel > *main_chan) > { > GList *link; > > - for (link = main_chan->base.clients; link != NULL; link = link->next) { > + for (link = red_channel_get_clients(RED_CHANNEL(main_chan)); link != > NULL; link = link->next) { > RedChannelClient *rcc = link->data; > MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc); > main_channel_client_migrate_cancel_wait(mcc); > } > - main_chan->num_clients_mig_wait = 0; > + main_chan->priv->num_clients_mig_wait = 0; > } > > int main_channel_migrate_src_complete(MainChannel *main_chan, int success) > { > GList *link; > + GList *clients = red_channel_get_clients(RED_CHANNEL(main_chan)); > int semi_seamless_count = 0; > > spice_printerr(""); > > - if (!main_chan->base.clients) { > + if (!clients) { > spice_printerr("no peer connected"); > return 0; > } > > - for (link = main_chan->base.clients; link != NULL; link = link->next) { > + for (link = clients; link != NULL; link = link->next) { > RedChannelClient *rcc = link->data; > MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc); > if (main_channel_client_migrate_src_complete(mcc, success)) > @@ -805,3 +820,39 @@ int main_channel_migrate_src_complete(MainChannel > *main_chan, int success) > } > return semi_seamless_count; > } > + > +void main_channel_on_migrate_connected(MainChannel *main_channel, gboolean > seamless) > +{ > + g_return_if_fail(main_channel->priv->num_clients_mig_wait); > + g_warn_if_fail(!seamless || main_channel->priv->num_clients_mig_wait > == 1); > + if (!--main_channel->priv->num_clients_mig_wait) { > + > reds_on_main_migrate_connected(red_channel_get_server(RED_CHANNEL(main_channel)), > + seamless); > + } > +} > + > +static void > +main_channel_class_init(MainChannelClass *klass) > +{ > + GObjectClass *object_class = G_OBJECT_CLASS(klass); > + RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass); > + > + g_type_class_add_private(klass, sizeof(MainChannelPrivate)); > + > + 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_send_item; > + channel_class->hold_item = main_channel_hold_pipe_item; > + channel_class->release_item = main_channel_release_pipe_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; > +} > + > diff --git a/server/main-channel.h b/server/main-channel.h > index 43a2679..ce67241 100644 > --- a/server/main-channel.h > +++ b/server/main-channel.h > @@ -18,21 +18,47 @@ > #ifndef __MAIN_CHANNEL_H__ > #define __MAIN_CHANNEL_H__ > > +#include <glib-object.h> > #include <stdint.h> > #include <spice/vd_agent.h> > + > #include "common/marshaller.h" > #include "red-channel.h" > #include "main-channel-client.h" > > +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; > +typedef struct MainChannelPrivate MainChannelPrivate; > + > +struct MainChannel > +{ > + RedChannel parent; > + > + MainChannelPrivate *priv; > +}; > + > +struct MainChannelClass > +{ > + RedChannelClass parent_class; > +}; > + > +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; > @@ -41,13 +67,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); > @@ -77,5 +96,8 @@ int main_channel_migrate_connect(MainChannel *main_channel, > RedsMigSpice *mig_ta > void main_channel_migrate_cancel_wait(MainChannel *main_chan); > /* returns the number of clients for which SPICE_MSG_MAIN_MIGRATE_END was > sent*/ > int main_channel_migrate_src_complete(MainChannel *main_chan, int success); > +void main_channel_on_migrate_connected(MainChannel *main_channel, gboolean > seamless); > + > +G_END_DECLS > > #endif > diff --git a/server/red-channel-client-private.h > b/server/red-channel-client-private.h > index c7009fe..7fe54d0 100644 > --- a/server/red-channel-client-private.h > +++ b/server/red-channel-client-private.h > @@ -21,6 +21,25 @@ > #include "red-channel-client.h" > #include "red-channel.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; > + > struct RedChannelClientPrivate { > RedChannel *channel; > RedClient *client; > diff --git a/server/red-channel-client.c b/server/red-channel-client.c > index 1c0339b..5e937b6 100644 > --- a/server/red-channel-client.c > +++ b/server/red-channel-client.c > @@ -158,6 +158,8 @@ static const SpiceDataHeaderOpaque mini_header_wrapper = > {NULL, sizeof(SpiceMini > > static void red_channel_client_start_ping_timer(RedChannelClient *rcc, > uint32_t timeout) > { > + SpiceCoreInterfaceInternal *core; > + > if (!rcc->priv->latency_monitor.timer) { > return; > } > @@ -165,11 +167,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; > } > @@ -177,7 +183,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; > } > > @@ -252,10 +259,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); > @@ -312,7 +319,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); > @@ -438,7 +445,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) > @@ -468,12 +474,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 = (RedChannelClient *)opaque; > > rcc->priv->send_data.blocked = TRUE; > - rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch, > - SPICE_WATCH_EVENT_READ | > - SPICE_WATCH_EVENT_WRITE); > + 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) > @@ -533,9 +541,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; > } > > @@ -607,7 +615,7 @@ static void red_channel_client_send_item(RedChannelClient > *rcc, RedPipeItem *ite > red_channel_client_send_ping(rcc); > break; > default: > - rcc->priv->channel->channel_cbs.send_item(rcc, item); > + red_channel_send_item(rcc->priv->channel, rcc, item); > return; > } > free(item); > @@ -625,7 +633,7 @@ static void > red_channel_client_release_item(RedChannelClient *rcc, > free(item); > break; > default: > - rcc->priv->channel->channel_cbs.release_item(rcc, item, > item_pushed); > + red_channel_release_item(rcc->priv->channel, rcc, item, > item_pushed); > } > } > > @@ -670,9 +678,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_EVENT_READ); > + core->watch_update_mask(rcc->priv->stream->watch, > + SPICE_WATCH_EVENT_READ); > } > > if (red_channel_client_urgent_marshaller_is_active(rcc)) { > @@ -750,8 +759,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)); > } > > /* > @@ -792,6 +806,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)) { > @@ -802,18 +817,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; > } > @@ -826,8 +847,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); > } > @@ -835,12 +856,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); > } > } > } > @@ -861,9 +882,11 @@ static void red_channel_client_event(int fd, int event, > void *data) > > 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; > @@ -874,24 +897,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, > @@ -901,27 +928,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->incoming.serial = 1; > > self->outgoing.opaque = self; > - self->outgoing.cb = &self->priv->channel->outgoing_cb; > + self->outgoing.cb = > red_channel_get_outgoing_handler(self->priv->channel); > self->outgoing.pos = 0; > self->outgoing.size = 0; > > 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_READ, > - red_channel_client_event, > - self); > - self->priv->id = self->priv->channel->clients_num; > + 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, > @@ -981,8 +1007,9 @@ 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); > } > } > } > @@ -1001,13 +1028,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); > @@ -1024,7 +1052,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; > @@ -1259,8 +1288,10 @@ void red_channel_client_push(RedChannelClient *rcc) > } > if (red_channel_client_no_item_being_sent(rcc) && > ring_is_empty(&rcc->priv->pipe) > && rcc->priv->stream->watch) { > - > rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch, > - SPICE_WATCH_EVENT_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); > @@ -1331,11 +1362,12 @@ static void > red_channel_client_handle_pong(RedChannelClient *rcc, SpiceMsgPing * > red_channel_client_start_ping_timer(rcc, PING_TEST_TIMEOUT_MS); > } > > -static void red_channel_handle_migrate_flush_mark(RedChannelClient *rcc) > +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); > } > } > > @@ -1346,23 +1378,30 @@ static void > red_channel_handle_migrate_flush_mark(RedChannelClient *rcc) > // 3) source migrates to target > // 4) target sends data to all > // So need to make all the handlers work with per channel/client data (what > data exactly?) > -static void red_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t > size, void *message) > +static void red_channel_client_handle_migrate_data(RedChannelClient *rcc, > + uint32_t size, > + 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; > } > @@ -1394,11 +1433,11 @@ int > red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size, > spice_error("unexpected flush mark"); > return FALSE; > } > - red_channel_handle_migrate_flush_mark(rcc); > + red_channel_client_handle_migrate_flush_mark(rcc); > rcc->priv->wait_migrate_flush_mark = FALSE; > break; > case SPICE_MSGC_MIGRATE_DATA: > - red_channel_handle_migrate_data(rcc, size, message); > + red_channel_client_handle_migrate_data(rcc, size, message); > break; > case SPICE_MSGC_PONG: > red_channel_client_handle_pong(rcc, message); > @@ -1417,7 +1456,7 @@ void red_channel_client_init_send_data(RedChannelClient > *rcc, uint16_t msg_type, > rcc->priv->send_data.header.set_msg_type(&rcc->priv->send_data.header, > msg_type); > rcc->priv->send_data.item = item; > if (item) { > - rcc->priv->channel->channel_cbs.hold_item(rcc, item); > + red_channel_hold_item(rcc->priv->channel, rcc, item); > } > } > > @@ -1477,9 +1516,10 @@ static inline gboolean > client_pipe_add(RedChannelClient *rcc, RedPipeItem *item, > return FALSE; > } > if (ring_is_empty(&rcc->priv->pipe) && rcc->priv->stream->watch) { > - > rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch, > - SPICE_WATCH_EVENT_READ | > - SPICE_WATCH_EVENT_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); > } > rcc->priv->pipe_size++; > ring_add(pos, &item->link); > @@ -1558,7 +1598,7 @@ uint32_t > red_channel_client_get_pipe_size(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) > @@ -1611,27 +1651,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) > @@ -1688,7 +1731,7 @@ int > red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc, > end_time = UINT64_MAX; > } > > - rcc->priv->channel->channel_cbs.hold_item(rcc, item); > + red_channel_hold_item(rcc->priv->channel, rcc, item); > > if (red_channel_client_is_blocked(rcc)) { > red_channel_client_receive(rcc); > @@ -1771,13 +1814,19 @@ void > red_channel_client_pipe_remove_and_release(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, > - rcc->priv->wait_migrate_data); > + 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 d8cc317..6649485 100644 > --- a/server/red-channel-client.h > +++ b/server/red-channel-client.h > @@ -46,10 +46,10 @@ G_BEGIN_DECLS > #define RED_IS_CHANNEL_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), > RED_TYPE_CHANNEL_CLIENT)) > #define RED_CHANNEL_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), > RED_TYPE_CHANNEL_CLIENT, RedChannelClientClass)) > > -typedef struct RedChannel RedChannel; > typedef struct RedClient RedClient; > typedef struct IncomingHandler IncomingHandler; > > +typedef struct RedChannel RedChannel; > typedef struct RedChannelClient RedChannelClient; > typedef struct RedChannelClientClass RedChannelClientClass; > typedef struct RedChannelClientPrivate RedChannelClientPrivate; > @@ -161,8 +161,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 c714d90..df865f0 100644 > --- a/server/red-channel.c > +++ b/server/red-channel.c > @@ -65,9 +65,135 @@ > * from the channel's thread. > */ > > -void red_channel_receive(RedChannel *channel) > +G_DEFINE_ABSTRACT_TYPE(RedChannel, red_channel, G_TYPE_OBJECT) > + > +#define CHANNEL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), > RED_TYPE_CHANNEL, RedChannelPrivate)) > + > +struct RedChannelPrivate > +{ > + uint32_t type; > + uint32_t id; > + > + SpiceCoreInterfaceInternal *core; > + gboolean handle_acks; > + > + // RedChannel will hold only connected channel clients (logic - when > pushing pipe item to all channel clients, there > + // is no need to go over disconnect clients) > + // . While client will hold the channel clients till it is destroyed > + // and then it will destroy them as well. > + // However RCC still holds a reference to the Channel. > + // Maybe replace these logic with ref count? > + // TODO: rename to 'connected_clients'? > + GList *clients; > + > + RedChannelCapabilities local_caps; > + uint32_t migration_flags; > + > + void *data; > + > + OutgoingHandlerInterface outgoing_cb; > + IncomingHandlerInterface incoming_cb; > + > + ClientCbs client_cbs; > + // TODO: when different channel_clients are in different threads from > Channel -> need to protect! > + pthread_t thread_id; > + RedsState *reds; > +#ifdef RED_STATISTICS > + StatNodeRef stat; > + uint64_t *out_bytes_counter; > +#endif > +}; > + > +enum { > + PROP0, > + PROP_SPICE_SERVER, > + PROP_CORE_INTERFACE, > + PROP_TYPE, > + PROP_ID, > + PROP_HANDLE_ACKS, > + PROP_MIGRATION_FLAGS > +}; > + > +static void > +red_channel_get_property(GObject *object, > + guint property_id, > + GValue *value, > + GParamSpec *pspec) > { > - g_list_foreach(channel->clients, (GFunc)red_channel_client_receive, > NULL); > + 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) > +{ > + 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) > @@ -75,17 +201,170 @@ static void > red_channel_client_default_peer_on_error(RedChannelClient *rcc) > red_channel_client_disconnect(rcc); > } > > +static void red_channel_on_output(void *opaque, int n) > +{ > + RedChannelClient *rcc = opaque; > + RedChannel *self = red_channel_client_get_channel(rcc);; > + > + red_channel_client_on_output(opaque, n); > + > + stat_inc_counter(self->priv->reds, self->priv->out_bytes_counter, n); > +} > + > +static void > +red_channel_constructed(GObject *object) > +{ > + RedChannel *self = RED_CHANNEL(object); > + spice_debug("%p: channel type %d id %d thread_id 0x%lx", self, > + self->priv->type, self->priv->id, self->priv->thread_id); > + > + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); > + self->priv->incoming_cb.alloc_msg_buf = > + (alloc_msg_recv_buf_proc)klass->alloc_recv_buf; > + self->priv->incoming_cb.release_msg_buf = > + (release_msg_recv_buf_proc)klass->release_recv_buf; > + self->priv->incoming_cb.handle_message = > (handle_message_proc)klass->handle_message; > + self->priv->incoming_cb.handle_parsed = > (handle_parsed_proc)klass->handle_parsed; > + self->priv->incoming_cb.parser = klass->parser; > + > + G_OBJECT_CLASS(red_channel_parent_class)->constructed(object); > +} > + > +static void red_channel_client_default_connect(RedChannel *channel, > RedClient *client, > + RedsStream *stream, > + int migration, > + int num_common_caps, uint32_t > *common_caps, > + int num_caps, uint32_t *caps) > +{ > + spice_error("not implemented"); > +} > + > +static void red_channel_client_default_disconnect(RedChannelClient *base) > +{ > + red_channel_client_disconnect(base); > +} > + > +static void > +red_channel_class_init(RedChannelClass *klass) > +{ > + GObjectClass *object_class = G_OBJECT_CLASS(klass); > + > + g_type_class_add_private(klass, sizeof (RedChannelPrivate)); > + > + object_class->get_property = red_channel_get_property; > + object_class->set_property = red_channel_set_property; > + object_class->finalize = red_channel_finalize; > + object_class->constructed = red_channel_constructed; > + > + g_object_class_install_property(object_class, > + PROP_SPICE_SERVER, > + g_param_spec_pointer("spice-server", > + "spice-server", > + "The spice server > associated with this channel", > + G_PARAM_READWRITE | > + > G_PARAM_CONSTRUCT_ONLY > | > + > G_PARAM_STATIC_STRINGS)); > + > + g_object_class_install_property(object_class, > + PROP_CORE_INTERFACE, > + g_param_spec_pointer("core-interface", > + "core-interface", > + "The > SpiceCoreInterface server associated with this channel", > + G_PARAM_READWRITE | > + > G_PARAM_CONSTRUCT_ONLY > | > + > G_PARAM_STATIC_STRINGS)); > + > + /* FIXME: generate enums for this in spice-common? */ > + g_object_class_install_property(object_class, > + PROP_TYPE, > + g_param_spec_int("channel-type", > + "channel type", > + "Type of this channel", > + 0, > + SPICE_END_CHANNEL, > + 0, > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT_ONLY > | > + > G_PARAM_STATIC_STRINGS)); > + > + g_object_class_install_property(object_class, > + PROP_ID, > + g_param_spec_uint("id", > + "id", > + "ID of this channel", > + 0, > + G_MAXUINT, > + 0, > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT_ONLY > | > + > G_PARAM_STATIC_STRINGS)); > + > + g_object_class_install_property(object_class, > + PROP_HANDLE_ACKS, > + g_param_spec_boolean("handle-acks", > + "Handle ACKs", > + "Whether this > channel handles ACKs", > + FALSE, > + G_PARAM_READWRITE | > + > G_PARAM_CONSTRUCT_ONLY > | > + > G_PARAM_STATIC_STRINGS)); > + > + g_object_class_install_property(object_class, > + PROP_MIGRATION_FLAGS, > + g_param_spec_uint("migration-flags", > + "migration flags", > + "Migration flags for > this channel", > + 0, > + G_MAXUINT, > + 0, > + G_PARAM_READWRITE | > + G_PARAM_CONSTRUCT_ONLY > | > + > G_PARAM_STATIC_STRINGS)); > +} > + > +static void > +red_channel_init(RedChannel *self) > +{ > + self->priv = CHANNEL_PRIVATE(self); > + > + red_channel_set_common_cap(self, SPICE_COMMON_CAP_MINI_HEADER); > + self->priv->thread_id = pthread_self(); > + self->priv->out_bytes_counter = 0; > + > + // TODO: send incoming_cb as parameters instead of duplicating? > + self->priv->incoming_cb.on_error = > + (on_incoming_error_proc)red_channel_client_default_peer_on_error; > + self->priv->incoming_cb.on_input = red_channel_client_on_input; > + self->priv->outgoing_cb.get_msg_size = > red_channel_client_get_out_msg_size; > + self->priv->outgoing_cb.prepare = red_channel_client_prepare_out_msg; > + self->priv->outgoing_cb.on_block = red_channel_client_on_out_block; > + self->priv->outgoing_cb.on_error = > + (on_outgoing_error_proc)red_channel_client_default_peer_on_error; > + self->priv->outgoing_cb.on_msg_done = > red_channel_client_on_out_msg_done; > + self->priv->outgoing_cb.on_output = red_channel_on_output; > + > + self->priv->client_cbs.connect = red_channel_client_default_connect; > + self->priv->client_cbs.disconnect = > red_channel_client_default_disconnect; > + self->priv->client_cbs.migrate = red_channel_client_default_migrate; > +} > + > + > +void red_channel_receive(RedChannel *channel) > +{ > + g_list_foreach(channel->priv->clients, > (GFunc)red_channel_client_receive, NULL); > +} > + > void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc) > { > spice_assert(rcc); > - channel->clients = g_list_append(channel->clients, rcc); > + channel->priv->clients = g_list_append(channel->priv->clients, rcc); > } > > int red_channel_test_remote_common_cap(RedChannel *channel, uint32_t cap) > { > GList *link; > > - for (link = channel->clients; link != NULL; link = link->next) { > + for (link = channel->priv->clients; link != NULL; link = link->next) { > RedChannelClient *rcc = link->data; > > if (!red_channel_client_test_remote_common_cap(rcc, cap)) { > @@ -99,7 +378,7 @@ int red_channel_test_remote_cap(RedChannel *channel, > uint32_t cap) > { > GList *link; > > - for (link = channel->clients; link != NULL; link = link->next) { > + for (link = channel->priv->clients; link != NULL; link = link->next) { > RedChannelClient *rcc = link->data; > > if (!red_channel_client_test_remote_cap(rcc, cap)) { > @@ -136,7 +415,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; > @@ -146,190 +425,42 @@ int red_channel_is_waiting_for_migrate_data(RedChannel > *channel) > return FALSE; > } > spice_assert(n_clients == 1); > - rcc = channel->clients->data; > + rcc = channel->priv->clients->data; > 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 && channel_cbs->release_item); > - 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; > - memcpy(&channel->channel_cbs, channel_cbs, sizeof(ChannelCbs)); > - > - channel->reds = reds; > - channel->core = core; > - > - // TODO: send incoming_cb as parameters instead of duplicating? > - channel->incoming_cb.alloc_msg_buf = > (alloc_msg_recv_buf_proc)channel_cbs->alloc_recv_buf; > - channel->incoming_cb.release_msg_buf = > (release_msg_recv_buf_proc)channel_cbs->release_recv_buf; > - channel->incoming_cb.handle_message = > (handle_message_proc)handle_message; > - channel->incoming_cb.on_error = > - (on_incoming_error_proc)red_channel_client_default_peer_on_error; > - channel->incoming_cb.on_input = red_channel_client_on_input; > - channel->outgoing_cb.get_msg_size = red_channel_client_get_out_msg_size; > - channel->outgoing_cb.prepare = red_channel_client_prepare_out_msg; > - channel->outgoing_cb.on_block = red_channel_client_on_out_block; > - channel->outgoing_cb.on_error = > - (on_outgoing_error_proc)red_channel_client_default_peer_on_error; > - channel->outgoing_cb.on_msg_done = red_channel_client_on_out_msg_done; > - channel->outgoing_cb.on_output = red_channel_client_on_output; > - > - client_cbs.connect = red_channel_client_default_connect; > - client_cbs.disconnect = red_channel_client_default_disconnect; > - client_cbs.migrate = red_channel_client_default_migrate; > - > - red_channel_register_client_cbs(channel, &client_cbs, NULL); > - red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER); > - > - channel->thread_id = pthread_self(); > - > - channel->out_bytes_counter = 0; > - > - spice_debug("channel type %d id %d thread_id 0x%lx", > - channel->type, channel->id, channel->thread_id); > - return channel; > -} > - > -// TODO: red_worker can use this one > -static void dummy_watch_update_mask(SpiceWatch *watch, int event_mask) > -{ > -} > - > -static SpiceWatch *dummy_watch_add(const SpiceCoreInterfaceInternal *iface, > - int fd, int event_mask, SpiceWatchFunc > func, void *opaque) > -{ > - return NULL; // apparently allowed? > -} > - > -static void dummy_watch_remove(SpiceWatch *watch) > -{ > -} > - > -// TODO: actually, since I also use channel_client_dummy, no need for core. > Can be NULL > -static const SpiceCoreInterfaceInternal dummy_core = { > - .watch_update_mask = dummy_watch_update_mask, > - .watch_add = dummy_watch_add, > - .watch_remove = dummy_watch_remove, > -}; > - > -RedChannel *red_channel_create_dummy(int size, RedsState *reds, uint32_t > type, uint32_t id) > -{ > - RedChannel *channel; > - ClientCbs client_cbs = { NULL, }; > - > - spice_assert(size >= sizeof(*channel)); > - channel = spice_malloc0(size); > - channel->type = type; > - channel->id = id; > - channel->refs = 1; > - channel->reds = reds; > - channel->core = &dummy_core; > - client_cbs.connect = red_channel_client_default_connect; > - client_cbs.disconnect = red_channel_client_default_disconnect; > - client_cbs.migrate = red_channel_client_default_migrate; > - > - red_channel_register_client_cbs(channel, &client_cbs, NULL); > - red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER); > - > - channel->thread_id = pthread_self(); > - spice_debug("channel type %d id %d thread_id 0x%lx", > - channel->type, channel->id, channel->thread_id); > - > - channel->out_bytes_counter = 0; > - > - return channel; > -} > - > -static int do_nothing_handle_message(RedChannelClient *rcc, > - uint16_t type, > - uint32_t size, > - uint8_t *msg) > -{ > - return TRUE; > -} > - > -RedChannel *red_channel_create_parser(int size, > - RedsState *reds, > - const SpiceCoreInterfaceInternal > *core, > - uint32_t type, uint32_t id, > - int handle_acks, > - spice_parse_channel_func_t parser, > - channel_handle_parsed_proc > handle_parsed, > - const ChannelCbs *channel_cbs, > - uint32_t migration_flags) > +void red_channel_set_stat_node(RedChannel *channel, StatNodeRef stat) > { > - RedChannel *channel = red_channel_create(size, reds, core, type, id, > - handle_acks, > - do_nothing_handle_message, > - channel_cbs, > - migration_flags); > - > - if (channel == NULL) { > - return NULL; > - } > - channel->incoming_cb.handle_parsed = (handle_parsed_proc)handle_parsed; > - channel->incoming_cb.parser = parser; > + spice_return_if_fail(channel != NULL); > + spice_return_if_fail(channel->priv->stat == 0); > > - return channel; > +#ifdef RED_STATISTICS > + channel->priv->stat = stat; > + channel->priv->out_bytes_counter = stat_add_counter(channel->priv->reds, > stat, "out_bytes", TRUE); > +#endif > } > > -void red_channel_set_stat_node(RedChannel *channel, StatNodeRef stat) > +StatNodeRef red_channel_get_stat_node(RedChannel *channel) > { > - spice_return_if_fail(channel != NULL); > - spice_return_if_fail(channel->stat == 0); > - > #ifdef RED_STATISTICS > - channel->stat = stat; > - channel->out_bytes_counter = stat_add_counter(channel->reds, stat, > "out_bytes", TRUE); > + return channel->priv->stat; > #endif > + return 0; > } > > void red_channel_register_client_cbs(RedChannel *channel, const ClientCbs > *client_cbs, gpointer cbs_data) > { > - spice_assert(client_cbs->connect || channel->type == > SPICE_CHANNEL_MAIN); > - channel->client_cbs.connect = client_cbs->connect; > + spice_assert(client_cbs->connect || channel->priv->type == > SPICE_CHANNEL_MAIN); > + channel->priv->client_cbs.connect = client_cbs->connect; > > if (client_cbs->disconnect) { > - channel->client_cbs.disconnect = client_cbs->disconnect; > + channel->priv->client_cbs.disconnect = client_cbs->disconnect; > } > > if (client_cbs->migrate) { > - channel->client_cbs.migrate = client_cbs->migrate; > + channel->priv->client_cbs.migrate = client_cbs->migrate; > } > - channel->data = cbs_data; > + channel->priv->data = cbs_data; > } > > int test_capability(const uint32_t *caps, int num_caps, uint32_t cap) > @@ -356,32 +487,12 @@ static void add_capability(uint32_t **caps, int > *num_caps, uint32_t cap) > > void red_channel_set_common_cap(RedChannel *channel, uint32_t cap) > { > - add_capability(&channel->local_caps.common_caps, > &channel->local_caps.num_common_caps, cap); > + add_capability(&channel->priv->local_caps.common_caps, > &channel->priv->local_caps.num_common_caps, cap); > } > > void red_channel_set_cap(RedChannel *channel, uint32_t cap) > { > - add_capability(&channel->local_caps.caps, &channel->local_caps.num_caps, > cap); > -} > - > -void red_channel_ref(RedChannel *channel) > -{ > - channel->refs++; > -} > - > -void red_channel_unref(RedChannel *channel) > -{ > - if (--channel->refs == 0) { > - if (channel->local_caps.num_common_caps) { > - free(channel->local_caps.common_caps); > - } > - > - if (channel->local_caps.num_caps) { > - free(channel->local_caps.caps); > - } > - > - free(channel); > - } > + add_capability(&channel->priv->local_caps.caps, > &channel->priv->local_caps.num_caps, cap); > } > > void red_channel_destroy(RedChannel *channel) > @@ -390,13 +501,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) > @@ -405,14 +516,14 @@ void red_channel_push(RedChannel *channel) > return; > } > > - g_list_foreach(channel->clients, (GFunc)red_channel_client_push, NULL); > + g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_push, > NULL); > } > > // TODO: this function doesn't make sense because the window should be > client (WAN/LAN) > // specific > void red_channel_init_outgoing_messages_window(RedChannel *channel) > { > - g_list_foreach(channel->clients, > (GFunc)red_channel_client_init_outgoing_messages_window, NULL); > + g_list_foreach(channel->priv->clients, > (GFunc)red_channel_client_init_outgoing_messages_window, NULL); > } > > static void red_channel_client_pipe_add_type_proxy(gpointer data, gpointer > user_data) > @@ -423,7 +534,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)); > } > > @@ -435,12 +546,12 @@ static void > red_channel_client_pipe_add_empty_msg_proxy(gpointer data, gpointer > > void red_channel_pipes_add_empty_msg(RedChannel *channel, int msg_type) > { > - g_list_foreach(channel->clients, > red_channel_client_pipe_add_empty_msg_proxy, GINT_TO_POINTER(msg_type)); > + g_list_foreach(channel->priv->clients, > red_channel_client_pipe_add_empty_msg_proxy, GINT_TO_POINTER(msg_type)); > } > > int red_channel_is_connected(RedChannel *channel) > { > - return channel && channel->clients; > + return channel && channel->priv->clients; > } > > void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc) > @@ -448,19 +559,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??? > } > > @@ -474,17 +585,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) > @@ -492,10 +621,10 @@ int red_channel_all_blocked(RedChannel *channel) > GList *link; > RedChannelClient *rcc; > > - if (!channel || !channel->clients) { > + if (!channel || !channel->priv->clients) { > return FALSE; > } > - for (link = channel->clients; link != NULL; link = link->next) { > + for (link = channel->priv->clients; link != NULL; link = link->next) { > rcc = link->data; > if (!red_channel_client_is_blocked(rcc)) { > return FALSE; > @@ -509,7 +638,7 @@ int red_channel_any_blocked(RedChannel *channel) > GList *link; > RedChannelClient *rcc; > > - for (link = channel->clients; link != NULL; link = link->next) { > + for (link = channel->priv->clients; link != NULL; link = link->next) { > rcc = link->data; > if (red_channel_client_is_blocked(rcc)) { > return TRUE; > @@ -523,10 +652,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 = channel->clients->data; > + rcc = channel->priv->clients->data; > stream = red_channel_client_get_stream(rcc); > > return stream->socket; > @@ -537,7 +666,7 @@ int red_channel_no_item_being_sent(RedChannel *channel) > GList *link; > RedChannelClient *rcc; > > - for (link = channel->clients; link != NULL; link = link->next) { > + for (link = channel->priv->clients; link != NULL; link = link->next) { > rcc = link->data; > if (!red_channel_client_no_item_being_sent(rcc)) { > return FALSE; > @@ -617,7 +746,7 @@ void red_client_migrate(RedClient *client) > rcc = link->data; > 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); > } > link = next; > } > @@ -650,7 +779,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); > @@ -670,7 +799,7 @@ RedChannelClient *red_client_get_channel(RedClient > *client, int type, int id) > RedChannel *channel; > rcc = link->data; > 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; > } > @@ -763,7 +892,7 @@ static int red_channel_pipes_create_batch(RedChannel > *channel, > spice_assert(creator != NULL); > spice_assert(pipe_add != NULL); > > - link = channel->clients; > + link = channel->priv->clients; > while (link != NULL) { > next = link->next; > rcc = link->data; > @@ -806,7 +935,7 @@ uint32_t red_channel_max_pipe_size(RedChannel *channel) > RedChannelClient *rcc; > uint32_t pipe_size = 0; > > - for (link = channel->clients; link != NULL; link = link->next) { > + for (link = channel->priv->clients; link != NULL; link = link->next) { > uint32_t new_size; > rcc = link->data; > new_size = red_channel_client_get_pipe_size(rcc); > @@ -821,7 +950,7 @@ uint32_t red_channel_min_pipe_size(RedChannel *channel) > RedChannelClient *rcc; > uint32_t pipe_size = ~0; > > - for (link = channel->clients; link != NULL; link = link->next) { > + for (link = channel->priv->clients; link != NULL; link = link->next) { > uint32_t new_size; > rcc = link->data; > new_size = red_channel_client_get_pipe_size(rcc); > @@ -836,7 +965,7 @@ uint32_t red_channel_sum_pipes_size(RedChannel *channel) > RedChannelClient *rcc; > uint32_t sum = 0; > > - for (link = channel->clients; link != NULL; link = link->next) { > + for (link = channel->priv->clients; link != NULL; link = link->next) { > rcc = link->data; > sum += red_channel_client_get_pipe_size(rcc); > } > @@ -879,5 +1008,116 @@ 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); > +} > + > +void red_channel_hold_item(RedChannel *self, RedChannelClient *rcc, > RedPipeItem *item) > +{ > + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); > + g_return_if_fail(klass->hold_item); > + > + klass->hold_item(rcc, item); > +} > + > +void red_channel_release_item(RedChannel *self, RedChannelClient *rcc, > + RedPipeItem *item, int item_pushed) > +{ > + RedChannelClass *klass = RED_CHANNEL_GET_CLASS(self); > + g_return_if_fail(klass->release_item); > + > + klass->release_item(rcc, item, item_pushed); > +} > + > +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 5c1d555..1b8abce 100644 > --- a/server/red-channel.h > +++ b/server/red-channel.h > @@ -36,9 +36,10 @@ > #include "red-pipe-item.h" > #include "red-channel-client.h" > > -/* Red Channel interface */ > +#include <glib-object.h> > + > +G_BEGIN_DECLS > > -typedef struct RedChannel RedChannel; > typedef struct RedClient RedClient; > > typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannelClient > *channel, > @@ -71,13 +72,53 @@ 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. > + * callbacks that are triggered from client events. > + * They should be called from the thread that handles the RedClient > */ > typedef struct { > + channel_client_connect_proc connect; > + channel_client_disconnect_proc disconnect; > + channel_client_migrate_proc migrate; > +} ClientCbs; > + > +int test_capability(const uint32_t *caps, int num_caps, uint32_t cap); > + > +#define RED_TYPE_CHANNEL red_channel_get_type() > + > +#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 RedChannel RedChannel; > +typedef struct RedChannelClass RedChannelClass; > +typedef struct RedChannelPrivate RedChannelPrivate; > + > +struct RedChannel > +{ > + GObject parent; > + > + RedChannelPrivate *priv; > +}; > + > +struct RedChannelClass > +{ > + GObjectClass parent_class; > + > + /* 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: 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; > @@ -88,18 +129,9 @@ typedef struct { > 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. > - * They should be called from the thread that handles the RedClient > - */ > -typedef struct { > - channel_client_connect_proc connect; > - channel_client_disconnect_proc disconnect; > - channel_client_migrate_proc migrate; > -} ClientCbs; > +/* Red Channel interface */ > > typedef struct RedChannelCapabilities { > int num_common_caps; > @@ -108,94 +140,20 @@ typedef struct RedChannelCapabilities { > uint32_t *caps; > } RedChannelCapabilities; > > -int test_capability(const uint32_t *caps, int num_caps, uint32_t cap); > - > -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; > - > -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; > - uint32_t clients_num; > - > - OutgoingHandlerInterface outgoing_cb; > - IncomingHandlerInterface incoming_cb; > - > - ChannelCbs channel_cbs; > - ClientCbs client_cbs; > - > - RedChannelCapabilities local_caps; > - uint32_t migration_flags; > - > - void *data; > - > - // 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 > -}; > - > -#define RED_CHANNEL(Channel) ((RedChannel *)(Channel)) > - > -/* 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); > +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); > > @@ -206,11 +164,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 > @@ -274,6 +227,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); > @@ -286,8 +242,38 @@ 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); > +void red_channel_hold_item(RedChannel *self, RedChannelClient *rcc, > RedPipeItem *item); > +void red_channel_release_item(RedChannel *channel, RedChannelClient *rcc, > + RedPipeItem *item, int item_pushed); > +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; > @@ -362,4 +348,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 9c30572..5da6916 100644 > --- a/server/red-parse-qxl.h > +++ b/server/red-parse-qxl.h > @@ -64,6 +64,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 ef39f0e..d255eb6 100644 > --- a/server/red-qxl.c > +++ b/server/red-qxl.c > @@ -81,7 +81,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; > @@ -108,7 +108,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; > @@ -125,11 +125,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, > @@ -142,7 +145,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; > @@ -170,7 +173,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; > > @@ -184,12 +187,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 281bc7a..a64d438 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 5be29aa..0d462b5 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> > @@ -97,33 +93,8 @@ static RedsState* red_worker_get_server(RedWorker > *worker); > > static int display_is_connected(RedWorker *worker) > { > - return (worker->display_channel && red_channel_is_connected( > - &worker->display_channel->common.base)); > -} > - > -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); > - > - /* SPICE_MSGC_MIGRATE_DATA is the only client message whose size is > dynamic */ > - if (type == SPICE_MSGC_MIGRATE_DATA) { > - return spice_malloc(size); > - } > - > - if (size > CHANNEL_RECEIVE_BUF_SIZE) { > - spice_critical("unexpected message size %u (max is %d)", size, > CHANNEL_RECEIVE_BUF_SIZE); > - return NULL; > - } > - return common->recv_buf; > -} > - > -static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, > uint32_t size, > - uint8_t* msg) > -{ > - if (type == SPICE_MSGC_MIGRATE_DATA) { > - free(msg); > - } > + return worker->display_channel && > + red_channel_is_connected(RED_CHANNEL(worker->display_channel)); > } > > void red_drawable_unref(RedDrawable *red_drawable) > @@ -244,7 +215,7 @@ static int red_process_display(RedWorker *worker, int > *ring_is_empty) > &update, ext_cmd.cmd.data)) { > break; > } > - if (!validate_surface(worker->display_channel, > update.surface_id)) { > + if (!display_channel_validate_surface(worker->display_channel, > update.surface_id)) { > spice_warning("Invalid surface in QXL_CMD_UPDATE"); > } else { > display_channel_draw(worker->display_channel, &update.area, > update.surface_id); > @@ -285,7 +256,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; > @@ -398,80 +369,6 @@ static void flush_all_qxl_commands(RedWorker *worker) > flush_cursor_commands(worker); > } > > -static int common_channel_config_socket(RedChannelClient *rcc) > -{ > - RedClient *client = red_channel_client_get_client(rcc); > - MainChannelClient *mcc = red_client_get_main(client); > - RedsStream *stream = red_channel_client_get_stream(rcc); > - CommonGraphicsChannelClient *ccc = COMMON_GRAPHICS_CHANNEL_CLIENT(rcc); > - int flags; > - int delay_val; > - gboolean low_bw; > - > - if ((flags = fcntl(stream->socket, F_GETFL)) == -1) { > - spice_warning("accept failed, %s", strerror(errno)); > - return FALSE; > - } > - > - if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) { > - spice_warning("accept failed, %s", strerror(errno)); > - return FALSE; > - } > - > - // TODO - this should be dynamic, not one time at channel creation > - low_bw = main_channel_client_is_low_bandwidth(mcc); > - common_graphics_channel_client_set_low_bandwidth(ccc, low_bw); > - delay_val = low_bw ? 0 : 1; > - /* FIXME: Using Nagle's Algorithm can lead to apparent delays, depending > - * on the delayed ack timeout on the other side. > - * Instead of using Nagle's, we need to implement message buffering on > - * the application level. > - * see: http://www.stuartcheshire.org/papers/NagleDelayedAck/ > - */ > - if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, > - sizeof(delay_val)) == -1) { > - if (errno != ENOTSUP) { > - spice_warning("setsockopt failed, %s", strerror(errno)); > - } > - } > - return TRUE; > -} > - > -CommonGraphicsChannel *red_worker_new_channel(RedWorker *worker, int size, > - const char *name, > - uint32_t channel_type, int > migration_flags, > - ChannelCbs *channel_cbs, > - channel_handle_parsed_proc > handle_parsed) > -{ > - RedChannel *channel = NULL; > - CommonGraphicsChannel *common; > - > - spice_return_val_if_fail(worker, NULL); > - spice_return_val_if_fail(channel_cbs, NULL); > - spice_return_val_if_fail(!channel_cbs->config_socket, NULL); > - spice_return_val_if_fail(!channel_cbs->alloc_recv_buf, NULL); > - spice_return_val_if_fail(!channel_cbs->release_recv_buf, NULL); > - > - 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, red_worker_get_server(worker), > - &worker->core, channel_type, > - worker->qxl->id, TRUE /* handle_acks > */, > - > spice_get_client_channel_parser(channel_type, > NULL), > - handle_parsed, > - channel_cbs, > - migration_flags); > - spice_return_val_if_fail(channel, NULL); > - red_channel_set_stat_node(channel, > stat_add_node(red_worker_get_server(worker), > - worker->stat, name, > TRUE)); > - > - common = (CommonGraphicsChannel *)channel; > - common->qxl = worker->qxl; > - return common; > -} > - > static void guest_set_client_capabilities(RedWorker *worker) > { > int i; > @@ -503,7 +400,7 @@ static void guest_set_client_capabilities(RedWorker > *worker) > return; > } > if ((worker->display_channel == NULL) || > - (RED_CHANNEL(worker->display_channel)->clients_num == 0)) { > + (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 > @@ -542,7 +439,7 @@ static void cursor_connect(RedWorker *worker, RedClient > *client, RedsStream *str > red_channel_client_ack_zero_messages_window(rcc); > red_channel_client_push_set_ack(rcc); > > - cursor_channel_init(channel, ccc); > + cursor_channel_do_init(channel, ccc); > } > > static void handle_dev_update_async(void *opaque, void *payload) > @@ -608,18 +505,6 @@ static void handle_dev_destroy_surfaces(void *opaque, > void *payload) > cursor_channel_reset(worker->cursor_channel); > } > > -static void display_update_monitors_config(DisplayChannel *display, > - QXLMonitorsConfig *config, > - uint16_t count, uint16_t > max_allowed) > -{ > - > - if (display->monitors_config) > - monitors_config_unref(display->monitors_config); > - > - display->monitors_config = > - monitors_config_new(config->heads, count, max_allowed); > -} > - > static void red_worker_push_monitors_config(RedWorker *worker) > { > DisplayChannelClient *dcc; > @@ -630,21 +515,6 @@ static void red_worker_push_monitors_config(RedWorker > *worker) > } > } > > -static void set_monitors_config_to_primary(DisplayChannel *display) > -{ > - DrawContext *context = &display->surfaces[0].context; > - QXLHead head = { 0, }; > - > - spice_return_if_fail(display->surfaces[0].context.canvas); > - > - if (display->monitors_config) > - monitors_config_unref(display->monitors_config); > - > - head.width = context->width; > - head.height = context->height; > - display->monitors_config = monitors_config_new(&head, 1, 1); > -} > - > static void dev_create_primary_surface(RedWorker *worker, uint32_t > surface_id, > QXLDevSurfaceCreate surface) > { > @@ -675,20 +545,22 @@ static void dev_create_primary_surface(RedWorker > *worker, uint32_t surface_id, > > display_channel_create_surface(display, 0, surface.width, > surface.height, surface.stride, surface.format, > line_0, surface.flags & > QXL_SURF_FLAG_KEEP_DATA, TRUE); > - set_monitors_config_to_primary(display); > + display_channel_set_monitors_config_to_primary(display); > > - if (display_is_connected(worker) && > !worker->display_channel->common.during_target_migrate) { > + if (display_is_connected(worker) && > + > !common_graphics_channel_get_during_target_migrate(COMMON_GRAPHICS_CHANNEL(worker->display_channel))) > + { > /* guest created primary, so it will (hopefully) send a > monitors_config > * now, don't send our own temporary one */ > 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, NULL); > + cursor_channel_do_init(worker->cursor_channel, NULL); > } > > static void handle_dev_create_primary_surface(void *opaque, void *payload) > @@ -703,12 +575,12 @@ static void destroy_primary_surface(RedWorker *worker, > uint32_t surface_id) > { > DisplayChannel *display = worker->display_channel; > > - if (!validate_surface(display, surface_id)) > + if (!display_channel_validate_surface(display, surface_id)) > return; > spice_warn_if_fail(surface_id == 0); > > spice_debug(NULL); > - if (!display->surfaces[surface_id].context.canvas) { > + if (!display_channel_surface_has_canvas(display, surface_id)) { > spice_warning("double destroy of primary surface"); > return; > } > @@ -717,8 +589,10 @@ static void destroy_primary_surface(RedWorker *worker, > uint32_t surface_id) > display_channel_destroy_surface_wait(display, 0); > display_channel_surface_unref(display, 0); > > + /* FIXME: accessing private date only for warning purposes... > spice_warn_if_fail(ring_is_empty(&display->streams)); > - spice_warn_if_fail(!display->surfaces[surface_id].context.canvas); > + */ > + spice_warn_if_fail(!display_channel_surface_has_canvas(display, > surface_id)); > > cursor_channel_reset(worker->cursor_channel); > } > @@ -784,10 +658,10 @@ static void handle_dev_start(void *opaque, void > *payload) > > spice_assert(!worker->running); > if (worker->cursor_channel) { > - > COMMON_GRAPHICS_CHANNEL(worker->cursor_channel)->during_target_migrate > = FALSE; > + > common_graphics_channel_set_during_target_migrate(COMMON_GRAPHICS_CHANNEL(worker->cursor_channel), > FALSE); > } > if (worker->display_channel) { > - worker->display_channel->common.during_target_migrate = FALSE; > + > common_graphics_channel_set_during_target_migrate(COMMON_GRAPHICS_CHANNEL(worker->display_channel), > FALSE); > display_channel_wait_for_migrate_data(worker->display_channel); > } > worker->running = TRUE; > @@ -807,16 +681,18 @@ 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); > // streams? but without streams also leak > +#if FIXME > spice_debug("OOM1 #draw=%u, #glz_draw=%u current %u pipes %u", > display->drawable_count, > display->glz_drawable_count, > display->current_size, > red_channel_sum_pipes_size(display_red_channel)); > +#endif > while (red_process_display(worker, &ring_is_empty)) { > red_channel_push(display_red_channel); > } > @@ -824,12 +700,14 @@ static void handle_dev_oom(void *opaque, void *payload) > display_channel_free_some(worker->display_channel); > red_qxl_flush_resources(worker->qxl); > } > +#if FIXME > spice_debug("OOM2 #draw=%u, #glz_draw=%u current %u pipes %u", > display->drawable_count, > display->glz_drawable_count, > display->current_size, > red_channel_sum_pipes_size(display_red_channel)); > red_qxl_clear_pending(worker->qxl->st, RED_DISPATCHER_PENDING_OOM); > +#endif > } > > static void handle_dev_reset_cursor(void *opaque, void *payload) > @@ -842,9 +720,7 @@ static void handle_dev_reset_cursor(void *opaque, void > *payload) > static void handle_dev_reset_image_cache(void *opaque, void *payload) > { > RedWorker *worker = opaque; > - DisplayChannel *display = worker->display_channel; > - > - image_cache_reset(&display->image_cache); > + display_channel_reset_image_cache(worker->display_channel); > } > > static void handle_dev_destroy_surface_wait_async(void *opaque, void > *payload) > @@ -964,7 +840,7 @@ static void handle_dev_monitors_config_async(void > *opaque, void *payload) > /* TODO: raise guest bug (requires added QXL interface) */ > return; > } > - display_update_monitors_config(worker->display_channel, > dev_monitors_config, > + display_channel_update_monitors_config(worker->display_channel, > dev_monitors_config, > MIN(count, msg->max_monitors), > MIN(max_allowed, msg->max_monitors)); > red_worker_push_monitors_config(worker); > @@ -1509,17 +1385,28 @@ RedWorker* red_worker_new(QXLInstance *qxl, > > worker->event_timeout = INF_EVENT_WAIT; > > - worker->cursor_channel = cursor_channel_new(worker); > + worker->cursor_channel = cursor_channel_new(reds, worker->qxl, > &worker->core); > + red_channel_set_stat_node(RED_CHANNEL(worker->cursor_channel), > + stat_add_node(red_worker_get_server(worker), > + worker->stat, > + "cursor_channel", TRUE)); > channel = RED_CHANNEL(worker->cursor_channel); > 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 > - worker->display_channel = display_channel_new(reds, worker, FALSE, > reds_get_streaming_video(reds), > + worker->display_channel = display_channel_new(reds, worker->qxl, > &worker->core, > + FALSE, > reds_get_streaming_video(reds), > init_info.n_surfaces); > + red_channel_set_stat_node(RED_CHANNEL(worker->display_channel), > + stat_add_node(red_worker_get_server(worker), > + worker->stat, > + "display_channel", TRUE)); > > channel = RED_CHANNEL(worker->display_channel); > 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); > @@ -1536,8 +1423,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 501128b..ebc5a97 100644 > --- a/server/red-worker.h > +++ b/server/red-worker.h > @@ -25,73 +25,9 @@ > > typedef struct RedWorker RedWorker; > > -#define COMMON_CLIENT_TIMEOUT (NSEC_PER_SEC * 30) > - > -#define CHANNEL_RECEIVE_BUF_SIZE 1024 > -typedef struct CommonGraphicsChannel { > - RedChannel base; // Must be the first thing > - > - QXLInstance *qxl; > - uint8_t recv_buf[CHANNEL_RECEIVE_BUF_SIZE]; > - uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme. > - int during_target_migrate; /* TRUE when the client that is associated > with the channel > - is during migration. Turned off when the > vm is started. > - The flag is used to avoid sending messages > that are artifacts > - of the transition from stopped vm to > loaded vm (e.g., recreation > - of the primary surface) */ > -} CommonGraphicsChannel; > - > -#define COMMON_GRAPHICS_CHANNEL(Channel) ((CommonGraphicsChannel*)(Channel)) > - > -enum { > - RED_PIPE_ITEM_TYPE_VERB = RED_PIPE_ITEM_TYPE_CHANNEL_BASE, > - RED_PIPE_ITEM_TYPE_INVAL_ONE, > - > - RED_PIPE_ITEM_TYPE_COMMON_LAST > -}; > - > -typedef struct RedVerbItem { > - RedPipeItem base; > - uint16_t verb; > -} RedVerbItem; > - > -static inline void red_marshall_verb(RedChannelClient *rcc, RedVerbItem > *item) > -{ > - red_channel_client_init_send_data(rcc, item->verb, NULL); > -} > - > -static inline void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb) > -{ > - RedVerbItem *item = spice_new(RedVerbItem, 1); > - > - red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_VERB); > - item->verb = verb; > - red_channel_client_pipe_add(rcc, &item->base); > -} > - > -static inline void red_pipe_add_verb_proxy(RedChannelClient *rcc, gpointer > data) > -{ > - uint16_t verb = GPOINTER_TO_UINT(data); > - red_pipe_add_verb(rcc, verb); > -} > - > - > -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)); > -} > - > RedWorker* red_worker_new(QXLInstance *qxl, > const ClientCbs *client_cursor_cbs, > const ClientCbs *client_display_cbs); > bool red_worker_run(RedWorker *worker); > > -void red_drawable_unref(RedDrawable *red_drawable); > - > -CommonGraphicsChannel *red_worker_new_channel(RedWorker *worker, int size, > - const char *name, > - uint32_t channel_type, int > migration_flags, > - ChannelCbs *channel_cbs, > - channel_handle_parsed_proc > handle_parsed); > - > #endif > diff --git a/server/reds-private.h b/server/reds-private.h > index 74a251b..4b86d2d 100644 > --- a/server/reds-private.h > +++ b/server/reds-private.h > @@ -120,8 +120,7 @@ struct RedsState { > Ring mig_target_clients; > int num_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 9f5551e..27fc5da 100644 > --- a/server/reds.c > +++ b/server/reds.c > @@ -463,15 +463,13 @@ void stat_update_value(RedsState *reds, uint32_t value) > 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"); > } > @@ -479,11 +477,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; > } > } > @@ -552,7 +552,7 @@ static void reds_reset_vdp(RedsState *reds) > * In addition, there used to be a misshandling of AGENT_TOKENS message > in spice-gtk: it > * overrides the amount of tokens, instead of adding the given amount. > */ > - if (red_channel_test_remote_cap(&reds->main_channel->base, > + if (red_channel_test_remote_cap(RED_CHANNEL(reds->main_channel), > SPICE_MAIN_CAP_AGENT_CONNECTED_TOKENS)) > { > dev->priv->agent_attached = FALSE; > } else { > @@ -743,7 +743,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); > } > } > @@ -995,7 +995,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: > @@ -1007,23 +1009,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)); > } > } > > @@ -1034,7 +1038,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); > > @@ -1546,12 +1550,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); > @@ -1888,13 +1892,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); > } > > /* > @@ -3123,7 +3127,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 > @@ -3442,7 +3446,6 @@ 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); > ring_init(&reds->mig_target_clients); > reds->char_devices = NULL; > reds->mig_wait_disconnect_clients = NULL; > @@ -3986,7 +3989,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 ec42960..c681d39 100644 > --- a/server/smartcard.c > +++ b/server/smartcard.c > @@ -49,6 +49,61 @@ > // 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); > +} > + > +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)) > @@ -74,10 +129,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]; > @@ -531,43 +582,53 @@ 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.hold_item = smartcard_channel_hold_pipe_item; > - channel_cbs.release_item = smartcard_channel_release_pipe_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_client_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->hold_item = smartcard_channel_hold_pipe_item; > + channel_class->release_item = smartcard_channel_release_pipe_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 e87428f..6982be3 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 "main-channel-client.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); > @@ -999,12 +1002,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); > @@ -1059,6 +1064,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; > @@ -1078,6 +1084,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; > @@ -1146,7 +1153,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, > @@ -1214,7 +1223,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); > > @@ -1243,7 +1252,7 @@ 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; > @@ -1272,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); > @@ -1463,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); > > @@ -1501,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) { > @@ -1543,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; > @@ -1572,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; > @@ -1629,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 0b37b4a..6441542 100644 > --- a/server/spicevmc.c > +++ b/server/spicevmc.c > @@ -52,16 +52,6 @@ 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)) > @@ -89,6 +79,133 @@ 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 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); > + > + 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); > +} > + > +SpiceVmcState *spice_vmc_state_new(RedsState *reds, uint8_t channel_type, > SpiceCharDeviceInstance *sin) > +{ > + static uint8_t id[256] = { 0, }; > + return g_object_new(SPICE_TYPE_VMC_STATE, > + "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; > @@ -117,17 +234,17 @@ 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); > - red_pipe_item_init(&msg_item->base, > RED_PIPE_ITEM_TYPE_SPICEVMC_DATA); > + red_pipe_item_init_full(&msg_item->base, > RED_PIPE_ITEM_TYPE_SPICEVMC_DATA, free); > } 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, > @@ -137,7 +254,7 @@ static RedPipeItem > *spicevmc_chardev_read_msg_from_dev(SpiceCharDeviceInstance * > msg_item->buf_used = n; > return (RedPipeItem *)msg_item; > } else { > - state->pipe_item = msg_item; > + state->priv->pipe_item = msg_item; > return NULL; > } > } > @@ -149,21 +266,21 @@ static void > spicevmc_chardev_send_msg_to_client(RedPipeItem *msg, > SpiceVmcState *state = opaque; > RedVmcPipeItem *vmc_msg = (RedVmcPipeItem *)msg; > > - 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(vmc_msg); > - red_channel_client_pipe_add_push(state->rcc, (RedPipeItem *)vmc_msg); > + red_channel_client_pipe_add_push(state->priv->rcc, (RedPipeItem > *)vmc_msg); > } > > static void spicevmc_port_send_init(RedChannelClient *rcc) > { > RedChannel *channel = red_channel_client_get_channel(rcc); > - SpiceVmcState *state = SPICE_CONTAINEROF(channel, SpiceVmcState, > channel); > - SpiceCharDeviceInstance *sin = state->chardev_sin; > + SpiceVmcState *state = SPICE_VMC_STATE(channel); > + 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); > } > > @@ -188,10 +305,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) > @@ -199,8 +316,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) { > @@ -224,19 +343,19 @@ static void > spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc) > return; > } > > - state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel); > + state = SPICE_VMC_STATE(channel); > > - if (state->recv_from_client_buf) { /* partial message which wasn't > pushed to device */ > - red_char_device_write_buffer_release(state->chardev, > state->recv_from_client_buf); > - state->recv_from_client_buf = NULL; > + if (state->priv->recv_from_client_buf) { /* partial message which wasn't > pushed to device */ > + red_char_device_write_buffer_release(state->priv->chardev, > state->priv->recv_from_client_buf); > + state->priv->recv_from_client_buf = NULL; > } > > - 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); > } > } > > @@ -245,17 +364,17 @@ 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); > } > } > > 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 int > spicevmc_channel_client_handle_migrate_flush_mark(RedChannelClient *rcc) > @@ -283,7 +402,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 spicevmc_red_channel_client_handle_message(RedChannelClient *rcc, > @@ -295,14 +414,14 @@ static int > spicevmc_red_channel_client_handle_message(RedChannelClient *rcc, > 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_PORT_EVENT: > if (size != sizeof(uint8_t)) { > @@ -310,7 +429,7 @@ static int > spicevmc_red_channel_client_handle_message(RedChannelClient *rcc, > return FALSE; > } > if (sif->base.minor_version >= 2 && sif->event != NULL) > - sif->event(state->chardev_sin, *msg); > + sif->event(state->priv->chardev_sin, *msg); > break; > default: > return red_channel_client_handle_message(rcc, size, type, msg); > @@ -327,20 +446,20 @@ static uint8_t > *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, > RedChannel *channel = red_channel_client_get_channel(rcc); > RedClient *client = red_channel_client_get_client(rcc); > > - state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel); > + state = SPICE_VMC_STATE(channel); > > 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); > @@ -356,13 +475,14 @@ static void > spicevmc_red_channel_release_msg_rcv_buf(RedChannelClient *rcc, > SpiceVmcState *state; > RedChannel *channel = red_channel_client_get_channel(rcc); > > - state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel); > + state = SPICE_VMC_STATE(channel); > > switch (type) { > case SPICE_MSGC_SPICEVMC_DATA: > - if (state->recv_from_client_buf) { /* buffer wasn't pushed to device > */ > - red_char_device_write_buffer_release(state->chardev, > state->recv_from_client_buf); > - state->recv_from_client_buf = NULL; > + if (state->priv->recv_from_client_buf) { /* buffer wasn't pushed to > device */ > + red_char_device_write_buffer_release(state->priv->chardev, > + > state->priv->recv_from_client_buf); > + state->priv->recv_from_client_buf = NULL; > } > break; > default: > @@ -393,12 +513,12 @@ static void > spicevmc_red_channel_send_migrate_data(RedChannelClient *rcc, > SpiceVmcState *state; > RedChannel *channel = red_channel_client_get_channel(rcc); > > - state = SPICE_CONTAINEROF(channel, SpiceVmcState, channel); > + state = SPICE_VMC_STATE(channel); > red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item); > 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, > @@ -464,6 +584,40 @@ static void > spicevmc_red_channel_release_pipe_item(RedChannelClient *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_message = > spicevmc_red_channel_client_handle_message; > + > + 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->hold_item = spicevmc_red_channel_hold_pipe_item; > + channel_class->release_item = spicevmc_red_channel_release_pipe_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_READWRITE | > + > G_PARAM_CONSTRUCT_ONLY > | > + > G_PARAM_STATIC_STRINGS)); > +} > + > 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) > @@ -472,13 +626,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); > @@ -490,21 +646,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_for_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); > } > @@ -514,37 +670,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, }; > - > - 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.hold_item = spicevmc_red_channel_hold_pipe_item; > - channel_cbs.release_item = spicevmc_red_channel_release_pipe_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(sizeof(SpiceVmcState), reds, > - reds_get_core_interface(reds), > channel_type, id[channel_type]++, > - FALSE /* handle_acks */, > - > spicevmc_red_channel_client_handle_message, > - &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); > - > - state->chardev = red_char_device_spicevmc_new(sin, reds, state); > - state->chardev_sin = sin; > + SpiceVmcState *state = spice_vmc_state_new(reds, channel_type, sin); > > - reds_register_channel(reds, &state->channel); > - return state->chardev; > + return state->priv->chardev; > } > > /* Must be called from RedClient handling thread. */ > @@ -555,17 +683,18 @@ void spicevmc_device_disconnect(RedsState *reds, > SpiceCharDeviceInstance *sin) > /* FIXME */ > state = (SpiceVmcState > *)red_char_device_opaque_get((RedCharDevice*)sin->st); > > - if (state->recv_from_client_buf) { > - red_char_device_write_buffer_release(state->chardev, > state->recv_from_client_buf); > + if (state->priv->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) > @@ -580,16 +709,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 47a6924..004e886 100644 > --- a/server/stream.c > +++ b/server/stream.c > @@ -20,13 +20,14 @@ > > #include "stream.h" > #include "display-channel.h" > +#include "display-channel-private.h" > #include "main-channel-client.h" > > #define FPS_TEST_INTERVAL 1 > #define FOREACH_STREAMS(display, item) \ > - for (item = ring_get_head(&(display)->streams); \ > + for (item = ring_get_head(&(display)->priv->streams); \ > item != NULL; \ > - item = ring_next(&(display)->streams, item)) > + item = ring_next(&(display)->priv->streams, item)) > > void stream_agent_stats_print(StreamAgent *agent) > { > @@ -72,11 +73,11 @@ void stream_stop(DisplayChannel *display, Stream *stream) > spice_return_if_fail(ring_item_is_linked(&stream->link)); > spice_return_if_fail(!stream->current); > > - spice_debug("stream %d", get_stream_id(display, stream)); > + spice_debug("stream %d", display_channel_get_stream_id(display, > stream)); > FOREACH_DCC(display, link, next, dcc) { > StreamAgent *stream_agent; > > - stream_agent = dcc_get_stream_agent(dcc, get_stream_id(display, > stream)); > + stream_agent = dcc_get_stream_agent(dcc, > display_channel_get_stream_id(display, stream)); > region_clear(&stream_agent->vis_region); > region_clear(&stream_agent->clip); > spice_assert(!red_pipe_item_is_linked(&stream_agent->destroy_item)); > @@ -94,25 +95,25 @@ void stream_stop(DisplayChannel *display, Stream *stream) > red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), > &stream_agent->destroy_item); > stream_agent_stats_print(stream_agent); > } > - display->streams_size_total -= stream->width * stream->height; > + display->priv->streams_size_total -= stream->width * stream->height; > ring_remove(&stream->link); > stream_unref(display, stream); > } > > static void stream_free(DisplayChannel *display, Stream *stream) > { > - stream->next = display->free_streams; > - display->free_streams = stream; > + stream->next = display->priv->free_streams; > + display->priv->free_streams = stream; > } > > void display_channel_init_streams(DisplayChannel *display) > { > int i; > > - ring_init(&display->streams); > - display->free_streams = NULL; > + ring_init(&display->priv->streams); > + display->priv->free_streams = NULL; > for (i = 0; i < NUM_STREAMS; i++) { > - Stream *stream = &display->streams_buf[i]; > + Stream *stream = &display->priv->streams_buf[i]; > ring_item_init(&stream->link); > stream_free(display, stream); > } > @@ -126,7 +127,7 @@ void stream_unref(DisplayChannel *display, Stream > *stream) > spice_warn_if_fail(!ring_item_is_linked(&stream->link)); > > stream_free(display, stream); > - display->stream_count--; > + display->priv->stream_count--; > } > > void stream_agent_unref(DisplayChannel *display, StreamAgent *agent) > @@ -169,7 +170,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->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; > } > @@ -284,7 +285,7 @@ static void attach_stream(DisplayChannel *display, > Drawable *drawable, Stream *s > StreamAgent *agent; > QRegion clip_in_draw_dest; > > - agent = dcc_get_stream_agent(dcc, get_stream_id(display, stream)); > + agent = dcc_get_stream_agent(dcc, > display_channel_get_stream_id(display, stream)); > region_or(&agent->vis_region, &drawable->tree_item.base.rgn); > > region_init(&clip_in_draw_dest); > @@ -335,7 +336,7 @@ static void before_reattach_stream(DisplayChannel > *display, > return; > } > > - index = get_stream_id(display, stream); > + index = display_channel_get_stream_id(display, stream); > DRAWABLE_FOREACH_DPI_SAFE(stream->current, ring_item, next, dpi) { > dcc = dpi->dcc; > agent = dcc_get_stream_agent(dcc, index); > @@ -392,11 +393,11 @@ static void before_reattach_stream(DisplayChannel > *display, > static Stream *display_channel_stream_try_new(DisplayChannel *display) > { > Stream *stream; > - if (!display->free_streams) { > + if (!display->priv->free_streams) { > return NULL; > } > - stream = display->free_streams; > - display->free_streams = display->free_streams->next; > + stream = display->priv->free_streams; > + display->priv->free_streams = display->priv->free_streams->next; > return stream; > } > > @@ -416,7 +417,7 @@ static void display_channel_create_stream(DisplayChannel > *display, Drawable *dra > spice_assert(drawable->red_drawable->type == QXL_DRAW_COPY); > src_rect = &drawable->red_drawable->u.copy.src_area; > > - ring_add(&display->streams, &stream->link); > + ring_add(&display->priv->streams, &stream->link); > stream->current = drawable; > stream->last_time = drawable->creation_time; > stream->width = src_rect->right - src_rect->left; > @@ -438,13 +439,13 @@ static void > display_channel_create_stream(DisplayChannel *display, Drawable *dra > } > stream->num_input_frames = 0; > stream->input_fps_start_time = drawable->creation_time; > - display->streams_size_total += stream->width * stream->height; > - display->stream_count++; > + display->priv->streams_size_total += stream->width * stream->height; > + display->priv->stream_count++; > FOREACH_DCC(display, link, next, dcc) { > dcc_create_stream(dcc, stream); > } > spice_debug("stream %d %dx%d (%d, %d) (%d, %d) %u fps", > - (int)(stream - display->streams_buf), stream->width, > + (int)(stream - display->priv->streams_buf), stream->width, > stream->height, stream->dest_area.left, > stream->dest_area.top, > stream->dest_area.right, stream->dest_area.bottom, > stream->input_fps); > @@ -520,7 +521,7 @@ void stream_trace_update(DisplayChannel *display, > Drawable *drawable) > } > } > > - trace = display->items_trace; > + trace = display->priv->items_trace; > trace_end = trace + NUM_TRACE_ITEMS; > for (; trace < trace_end; trace++) { > if (is_next_stream_frame(display, drawable, trace->width, > trace->height, > @@ -591,7 +592,7 @@ static void > dcc_update_streams_max_latency(DisplayChannelClient *dcc, StreamAgen > } > > dcc_set_max_stream_latency(dcc, 0); > - if (DCC_TO_DC(dcc)->stream_count == 1) { > + if (DCC_TO_DC(dcc)->priv->stream_count == 1) { > return; > } > for (i = 0; i < NUM_STREAMS; i++) { > @@ -650,7 +651,7 @@ static uint64_t get_initial_bit_rate(DisplayChannelClient > *dcc, Stream *stream) > /* dividing the available bandwidth among the active streams, and saving > * (1-RED_STREAM_CHANNEL_CAPACITY) of it for other messages */ > return (RED_STREAM_CHANNEL_CAPACITY * bit_rate * > - stream->width * stream->height) / > DCC_TO_DC(dcc)->streams_size_total; > + stream->width * stream->height) / > DCC_TO_DC(dcc)->priv->streams_size_total; > } > > static uint32_t get_roundtrip_ms(void *opaque) > @@ -703,7 +704,7 @@ static void update_client_playback_delay(void *opaque, > uint32_t delay_ms) > > void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream) > { > - StreamAgent *agent = dcc_get_stream_agent(dcc, > get_stream_id(DCC_TO_DC(dcc), stream)); > + StreamAgent *agent = dcc_get_stream_agent(dcc, > display_channel_get_stream_id(DCC_TO_DC(dcc), stream)); > > spice_return_if_fail(region_is_empty(&agent->vis_region)); > > @@ -741,7 +742,7 @@ void dcc_create_stream(DisplayChannelClient *dcc, Stream > *stream) > agent->report_id = rand(); > red_pipe_item_init(&report_pipe_item->pipe_item, > RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT); > - report_pipe_item->stream_id = get_stream_id(DCC_TO_DC(dcc), stream); > + report_pipe_item->stream_id = > display_channel_get_stream_id(DCC_TO_DC(dcc), stream); > red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), > &report_pipe_item->pipe_item); > } > #ifdef STREAM_STATS > @@ -782,7 +783,7 @@ static void > dcc_detach_stream_gracefully(DisplayChannelClient *dcc, > Drawable *update_area_limit) > { > DisplayChannel *display = DCC_TO_DC(dcc); > - int stream_id = get_stream_id(display, stream); > + int stream_id = display_channel_get_stream_id(display, stream); > StreamAgent *agent = dcc_get_stream_agent(dcc, stream_id); > > /* stopping the client from playing older frames at once*/ > @@ -868,7 +869,7 @@ static void detach_stream_gracefully(DisplayChannel > *display, Stream *stream, > */ > void stream_detach_behind(DisplayChannel *display, QRegion *region, Drawable > *drawable) > { > - Ring *ring = &display->streams; > + Ring *ring = &display->priv->streams; > RingItem *item = ring_get_head(ring); > GList *link, *next; > DisplayChannelClient *dcc; > @@ -880,12 +881,12 @@ void stream_detach_behind(DisplayChannel *display, > QRegion *region, Drawable *dr > item = ring_next(ring, item); > > FOREACH_DCC(display, link, next, dcc) { > - StreamAgent *agent = dcc_get_stream_agent(dcc, > get_stream_id(display, stream)); > + StreamAgent *agent = dcc_get_stream_agent(dcc, > display_channel_get_stream_id(display, stream)); > > if (region_intersects(&agent->vis_region, region)) { > dcc_detach_stream_gracefully(dcc, stream, drawable); > detach = 1; > - spice_debug("stream %d", get_stream_id(display, stream)); > + spice_debug("stream %d", > display_channel_get_stream_id(display, stream)); > } > } > if (detach && stream->current) { > @@ -904,7 +905,7 @@ void stream_detach_and_stop(DisplayChannel *display) > RingItem *stream_item; > > spice_debug(NULL); > - while ((stream_item = ring_get_head(&display->streams))) { > + while ((stream_item = ring_get_head(&display->priv->streams))) { > Stream *stream = SPICE_CONTAINEROF(stream_item, Stream, link); > > detach_stream_gracefully(display, stream, NULL); > @@ -914,7 +915,7 @@ void stream_detach_and_stop(DisplayChannel *display) > > void stream_timeout(DisplayChannel *display) > { > - Ring *ring = &display->streams; > + Ring *ring = &display->priv->streams; > RingItem *item; > > red_time_t now = spice_get_monotonic_time_ns(); > @@ -937,7 +938,7 @@ void stream_trace_add_drawable(DisplayChannel *display, > Drawable *item) > return; > } > > - trace = &display->items_trace[display->next_item_trace++ & > ITEMS_TRACE_MASK]; > + trace = &display->priv->items_trace[display->priv->next_item_trace++ & > ITEMS_TRACE_MASK]; > trace->time = item->creation_time; > trace->first_frame_time = item->first_frame_time; > trace->frames_count = item->frames_count; > diff --git a/server/stream.h b/server/stream.h > index 29071f5..f337059 100644 > --- a/server/stream.h > +++ b/server/stream.h > @@ -41,9 +41,6 @@ > #define RED_STREAM_DEFAULT_LOW_START_BIT_RATE (2.5 * 1024 * 1024) // 2.5Mbps > #define MAX_FPS 30 > > -/* move back to display_channel once struct private */ > -typedef struct DisplayChannel DisplayChannel; > - > typedef struct Stream Stream; > > typedef struct RedStreamActivateReportItem { _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel